如何“超载" python的打印功能“全局"? [英] How to "overload" python's print function "globally"?

查看:75
本文介绍了如何“超载" python的打印功能“全局"?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用python 2.6.6,我需要重载默认的python打印功能.我需要这样做,因为此代码可能在必须使用内置函数来生成输出的系统上使用,否则将不显示任何输出.

因此,举例来说,如果您有这样的python脚本:

from __future__ import print_function

def NewPrint(Str):
    with open("somefile.txt","a") as AFile:
        AFile.write(Str)

def OverloadPrint():
    global print
    print = NewPrint

OverloadPrint()
print("ha")

工作正常. 重载"打印的输入在NewPrint指定的文件中.

现在,考虑到这一点,我希望能够运行以上几行代码,并进行打印,以便在脚本的整个执行过程中执行NewPrint的操作.现在,如果我从另一个使用print的模块中调用一个函数,它将使用内置的print而不是我刚刚改写的print.我想这与名称空间和内置函数有关,但是我的python不够好.

我试图保持简单,但是看起来这引起了更多的混乱...

  1. 使打印过载的功能将打印到GUI,因此无需担心重定向 IF .
  2. 我知道我的示例并没有执行打印功能实际执行的操作.关于如何进行编码的一个更好的例子是(我所知道的还不是很好):

    def hli_print(*args, **kw):
        """
        print([object, ...], sep=' ', end='\n', file=sys.stdout)
        """
        sep = kw.get('sep', ' ')
        end = kw.get('end', '\n')
        File = kw.get('file', sys.stdout)
        args = [str(arg) for arg in args]
        string = sep.join(args) + end
        File.write(string)
        hli_Print(string)
    

  3. 从以上2处,您可以看到我必须用于打印到GUI"hli_Print"的函数,它是通过Swig包装程序公开的C ++函数.

  4. 我们仅使用标准库和我们自己的swig包装器,我们的开发人员也将print作为函数使用(习惯了3.X).因此,我实际上并不担心其他一些调用print并拥有其他功能的模块.

从所有评论中,我猜想仅仅使用一些print_()函数而不是print()(这是我们当前正在做的)可能是最好的,但是我真的很好奇,看看在python中是否可以照我说的做.

解决方案

我认为您的问题没有任何意义.

首先,如果您正在运行Python 2.6,则即使您自己的模块正在使用print函数,导入的所有内容等都将使用print语句.因此,重载该功能不会影响其他任何内容.

第二,您说我需要这样做,因为此代码可能在必须使用内置函数来生成输出的系统上使用,否则将不显示任何输出."好吧,您的NewPrint不是内置函数,因此仍然无济于事.

还值得注意的是,您的NewPrint并没有实现print函数的大部分功能,即使它实现了 的功能,它也会出错(print(s)将打印s 后跟换行符).因此,如果您用自己的 did 替换内置的print函数,最终将破坏大多数自己的代码以及您依赖的任何stdlib/第三方代码.

通过创建一个替换sys.stdout的类似文件的对象,您可以完成所需的工作.否则,我看不到任何方法.例如:

class FakeStdOut(object):
    # … lots of other stuff to implement or inherit
    def write(s):
        with open("somefile.txt", "a") as f:
            f.write(s)

def OverloadPrint():
    sys.stdout = FakeStdOut()

但是即使这行得通,也可能不是您真正想要的.对于快速且肮脏的脚本,在具有缺陷外壳的平台上,这有时是一个方便的主意.但是否则,从长远来看,这可能会给您带来比提供更好的解决方案更多的麻烦.这只是几处可能出错的地方(仅作为示例,而不是详尽的清单)

  • 如果您想更改输出到的文件,则必须修改脚本.如果您在外壳中使用>>,则可以不同地调用该脚本.
  • 正在阅读或调试代码的人(例如,您忘记了代码的工作三个月之后)会对发生的事情感到惊讶.
  • 一些stdlib/第三方/同事/等等.进行更改之前,您调用的代码将检查stdout是否为tty,并对其进行配置以进行交互式输出.
  • 在您有机会进行重定向之前,将打印一些代码,并且您将花费数小时来尝试找出如何重新排序以解决问题的方法.
  • 您必须知道如何完全实现类文件的对象",并且该概念在2.6中尚未完全定义,否则它将被某些代码破坏.
  • 在某个地方,您认为有一些代码正在执行print,但实际上是说log ging或写入sys.stderr或进行其他操作,因此您给自己一种错误的安全感您现在将所有内容都记录在somefile.txt中,直到6个月后,当您迫切需要缺少的信息来在客户站点调试问题时,才发现其他情况.

既然您已经编辑了问题,这里有一些进一步的回答:

从所有注释中,我猜想只是使用一些print_()函数而不是print()

是的,这是一个更合理的选择.但是我可能不会将其称为print_.而且,将执行或不执行"逻辑放入函数内部更为简单,而不是在全局名称之间来回交换实现(尤其是如果您不完全将代码包含在其中,则将在某个时候搞砸它)一个大模块).

我在一个具有类似用例的项目上工作:我们收到了一些消息,我们想转到syslogs,如果打开的话,还要转到GUI的日志窗口".因此,我们编写了一个glog函数,将其包装起来,没有人抱怨他们想编写print. (实际上,团队中至少有一个人很高兴他可以在调试时使用print进行快速脏的打印输出而不影响实际输出,尤其是当他必须调试GUI日志记录代码时.)

但这只是因为我们对新的(当时)logging模块没有任何经验.如今,我认为我将创建一个写入GUI窗口的logging Handler实现,然后添加该处理程序,并在所有地方使用标准的logging方法.听起来这可能是您的最佳选择.

另外,最后一个可能不相关的附带问题:

我们仅使用标准库和我们自己的swig包装器,我们的开发人员也将print作为函数使用(习惯了3.X).

那么为什么不首先使用3.x?显然,3.x具有实际的3.x标准库,而不是某种类似于3.x标准库的东西,如果您执行一些__future__语句,那么SWIG可以与3.x一起使用……

I am using python 2.6.6 and I need to overload the default python print function. I need to do it because this code may be used on a system where a built-in function has to be used to generate output, otherwise no output is displayed.

So, just for example, if you have a python script like this:

from __future__ import print_function

def NewPrint(Str):
    with open("somefile.txt","a") as AFile:
        AFile.write(Str)

def OverloadPrint():
    global print
    print = NewPrint

OverloadPrint()
print("ha")

It works fine. The input to the "overloaded" print is in the file specified by NewPrint.

Now with that in mind I would like to be able to run the couple of lines above and have print to do what NewPrint does during the entire execution of the script. Right now if I call a function from another module that uses print it will use the built-in print and not the one I just overwrote. I guess this has something to do with namespaces and built-ins, but my python is not good enough.

Edit:

I tried to keep simple, but looks like this caused more confusion...

  1. The function that overloads print will print to a GUI, so no need to care about redirection IF the function is overloaded.
  2. I know my example does not do what the print function actually does. A better example of how I am thinking of coding it is (still not great I know):

    def hli_print(*args, **kw):
        """
        print([object, ...], sep=' ', end='\n', file=sys.stdout)
        """
        sep = kw.get('sep', ' ')
        end = kw.get('end', '\n')
        File = kw.get('file', sys.stdout)
        args = [str(arg) for arg in args]
        string = sep.join(args) + end
        File.write(string)
        hli_Print(string)
    

  3. From 2 above you can see the function I have to use to print to the GUI "hli_Print" it is a C++ function exposed through a swig wrapper.

  4. We only use the standard library and our own swig wrappers, also our developers use print as a function (getting used to 3.X). So I did not really worry much about some other module calling print and having something else instead.

From all the comments I guess that just using some print_() function instead of print() (which is what we currently do) may be the best, but I got really curious to see if in python it would be possible to do what I described.

解决方案

I don't think your question makes any sense.

First, if you're running Python 2.6, everything you import, etc., will be using print statements, even if your own module is using the print function. So, overloading the function will not affect anything else.

Second, you say "I need to do it because this code may be used on a system where a built-in function has to be used to generate output, otherwise no output is displayed." Well, your NewPrint is not a built-in function, so this won't help anyway.

It's also worth noting that your NewPrint doesn't implement most of the functionality of the print function, and even the bit that it does implement, it does wrong (print(s) will print s followed by a newline). So, if you did replace the builtin print function with yours, you'd just end up breaking most of your own code and any stdlib/third-party code you depend on.

It may be that you can accomplish what you want by creating a file-like object that replaces sys.stdout. Otherwise, I can't see how anything could work. For example:

class FakeStdOut(object):
    # … lots of other stuff to implement or inherit
    def write(s):
        with open("somefile.txt", "a") as f:
            f.write(s)

def OverloadPrint():
    sys.stdout = FakeStdOut()

But even if this works, it probably isn't what you really want. For a quick&dirty script, on a platform with a defective shell, this is sometimes a handy idea. But otherwise, it will probably cause you more trouble in the long run than coming up with a better solution. Here's just a few things that can go wrong (just as examples, not an exhaustive list)

  • If you ever want to change the file the output goes to, you have to modify the script. If you instead used >> in the shell, you could just call the script differently.
  • Someone reading or debugging your code (like, say, you, three months after you forgot how it worked) will be surprised by what's going on.
  • Some stdlib/third-party/coworker/etc. code you call will check that stdout is a tty before you make the change, and configure itself for interactive output.
  • Some code will print before you got a chance to redirect, and you'll spend hours trying to figure out how to reorder things to work around the problem.
  • You have to know how to implement a 'file-like object' completely—and that concept is not fully defined in 2.6—or it will break with some code.
  • Somewhere, there's some code that you thought was printing, but it was actually, say, logging or writing to sys.stderr or doing something else, so you've given yourself a false sense of security that you're now logging everything in somefile.txt, and won't discover otherwise until 6 months later, when you desperately need that missing information to debug a problem at a customer site.

Since you've edited the question, here's some further responses:

From all the comments I guess that just using some print_() function instead of print()

Yes, that's a more reasonable option. But I probably wouldn't call it print_. And it's simpler to put the "do or do not" logic inside the function, instead of swapping implementations in and out of the global name (especially since you're going to screw that up at some point if your code isn't all in one big module).

I worked on a project with a similar use case: We had messages we wanted to go to the syslogs, and also go to a GUI "log window" if it was open. So we wrote a glog function that wrapped that up, and nobody complained that they wanted to write print instead. (In fact, at least one guy on the team was very happy that he could use print for quick-and-dirty printouts while debugging without affecting the real output, especially when he had to debug the GUI logging code.)

But that was just because we didn't have any experience with the new (back then) logging module. Nowadays, I think I'd create a logging Handler implementation that writes to the GUI window, and just add that handler, and use the standard logging methods everywhere. And it sounds like that might be the best option for you.

Also, one last probably-irrelevant side issue:

We only use the standard library and our own swig wrappers, also our developers use print as a function (getting used to 3.X).

So why not use 3.x in the first place? Obviously 3.x has the actual 3.x standard library, instead of something kind of close to the 3.x standard library if you do some __future__ statements, and SWIG works with 3.x…

这篇关于如何“超载" python的打印功能“全局"?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆