0

我有一种情况,我试图将一些大而复杂的 python 例程移植到线程环境中。

我希望能够在每次调用的基础上将函数print语句的输出重定向到其他地方(logging.Logger具体来说是a)。

我真的不想修改我正在编译的代码的源代码,因为我需要保持与调用这些模块的其他软件的向后兼容性(它是单线程的,并且通过简单地抓取写入的所有内容来捕获输出sys.stdout)。

我知道最好的选择是进行一些重写,但我在这里真的别无选择。

编辑-

或者,有什么方法可以覆盖 print 的本地定义以指向不同的函数?

然后我可以定义本地打印 = 系统打印,除非被 kwarg 覆盖,并且只涉及在每个例程开始时修改几行。

4

3 回答 3

6

在 Python2.6(和 2.7)中,您可以使用

from __future__ import print_function

然后您可以更改代码以使用该print()函数,就像使用 Python3 一样

这允许您创建一个名为 print 的模块全局或本地函数,该函数将优先于内置函数使用

例如。

from __future__ import print_function

def f(x, print=print):
    print(x*x)

f(5)
L=[]
f(6, print=L.append)
print(L)
于 2011-01-01T10:38:02.903 回答
3

修改源代码并不意味着破坏向后兼容性。

您需要做的是首先将每个 print 语句替换为对执行相同操作的函数的调用:

import sys
def _print(*args, **kw):
    sep = kw.get('sep', ' ')
    end = kw.get('end', '\n')
    file = kw.get('file', sys.stdout)
    file.write(sep.join(args))
    file.write(end)

def foo():
   # print "whatever","you","want"
   _print("whatever","you","want")

那么第二步就是直接停止使用_print函数,把它变成关键字参数:

def foo(_print=_print):
    ...

并确保更改所有内部函数调用以传递 _print 函数。

现在所有现有代码将继续工作并使用打印,但您可以传入任何您想要的 _print 函数。

请注意,_print 的签名与 Python 较新版本中的 print 函数的签名完全相同,因此一旦升级,您就可以将其更改为使用print(). 您也可以使用 2to3 迁移现有代码中的打印语句,这应该减少所需的编辑。

于 2011-01-01T10:32:09.583 回答
2

六十年代的某个人对如何解决这个问题有一个想法,但它需要一点外星技术。不幸的是,python 没有“当前环境”概念,这意味着除非在调用中将其指定为参数,否则您无法提供上下文。

为了处理这个特定的问题,如何用行为取决于线程特定上下文的类文件对象替换标准输出?这样源代码保持不变,但例如您可以为每个线程获取单独的日志。甚至可以很容易地以特定的每次调用方式执行此操作……例如:

class MyFakeStdout:
    def write(self, s):
        try:
            separate_logs[current_thread()].write(s)
        except KeyError:
            old_stdout.write(s)

然后具有将记录器本地设置为调用的功能(with

PS:我在标题中看到了“不触及标准输出”,但我认为这是因为您只想影响一些线程。在我看来,在仍然允许其他线程不受影响地工作的同时触摸它似乎与这个问题兼容。

于 2011-01-01T11:02:29.150 回答