覆盖内置功能

时间:2013-12-13 13:17:19

标签: python function built-in

我有一大堆使用“print”语句的代码。至于这样说:

print "foo"

而不是

print("foo")

我想改变输出。我可以在不改变所有印刷线的情况下这样做吗?例如,通过覆盖函数/语句?

4 个答案:

答案 0 :(得分:14)

Python 直接支持您要执行的操作:

from __future__ import print_function

顶部带有该行的任何模块都会将print语句视为函数,使代码与Python 2和3兼容。

这会将只是应用于print声明;你不能覆盖其他陈述。

这意味着您必须在该模块中的任何地方使用print()作为函数,但如果您愿意,您也可以提供自己的实现:

from __future__ import print_function
import __builtin__

def print(*args, **kwargs):
    __builtin__.print('Prefixed:', *args, **kwargs)

print('Hello world!')

另一种选择是使用上下文管理器捕获打印的语句,将输出从sys.stdout引导到您选择的内存中文件对象中:

from contextlib import contextmanager
import sys
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO


@contextmanager
def capture_sys_output():
    caputure_out = StringIO()
    current_out = sys.stdout
    try:
        sys.stdout = caputure_out
        yield caputure_out
    finally:
        sys.stdout = current_out

并使用上下文管理器包装要捕获print输出的所有块。以下是打印行前缀的示例:

with capture_sys_output as output:
    print 'Hello world!'

output = output.get_value()
for line in output.splitlines():
    print 'Prefixed:', line

甚至提供包装:

from contextlib import contextmanager
import sys

class Prefixer(object):
    def __init__(self, prefix, orig):
        self.prefix = prefix
        self.orig = orig
    def write(self, text):
        self.orig.write(self.prefix + text)
    def __getattr__(self, attr):
        return getattr(self.orig, attr)     

@contextmanager
def prefix_stdout(prefix):
    current_out = sys.stdout
    try:
        sys.stdout = Prefixer(prefix, current_out)
        yield
    finally:
        sys.stdout = current_out

并用作:

with prefix_stdout('Prefixed: '):
    print 'Hello world!'

但考虑到print语句通常以单独的块的形式将数据写入stdout;最后的换行符是单独的写。

答案 1 :(得分:6)

这会更改print语句的行为,而不会强制您更改

print "foo"

print("foo")

import sys
_stdout = sys.stdout

class MyStream(object):
    def __init__(self, target):
        self.target = target

    def write(self, s):
        s = 'Foo : {!r}'.format(s)
        self.target.write(s)
sys.stdout = MyStream(sys.stdout)
print 'Hi'
sys.stdout = _stdout   # return print to its old behavior

产量

Foo : 'Hi'

这可以通过上下文管理器加以解决,但是如果您不想将print语句更改为print函数,则可能不希望将{{1}包裹起来上下文管理器中的语句。


因此,更好,更文明的方式是使用

print

自动将代码中的所有2to3 --write --fix print test.py 语句(例如上面的test.py)更改为print个函数。然后,您可以通过重新定义print函数来更改行为:

print

产量

from __future__ import print_function
import __builtin__

def print(*args, **kwargs): 
    __builtin__.print('Foo:', *args, **kwargs)
print('Hi')

答案 2 :(得分:4)

在Python 2.x中,print是一个语句,因此可以在没有parens的情况下调用它。显然你正在使用它。

您无法覆盖内置的print语句。

但是,它将其输出写入sys.stdout。也许你可以用一些具有.write方法的对象覆盖sys.stdout,如下所示:

import sys
from StringIO import StringIO

s = StringIO()
sys.stdout = s

print "Hmmm."

assert s.getvalue() == "Hmmm.\n"

答案 3 :(得分:2)

在Python 2中,有一个print 语句,它是一种语言结构。因此,您将无法覆盖其行为。

在Python 3和Python 2中,如果你明确地启用它,你就有了print 功能。它确实需要括号,因此print "foo"不起作用,但你可以重新定义它的作用:

>>> from __future__ import print_function # for Python 2
>>> oldPrintFunction = print
>>> def print (*args, **kwargs):
        oldPrintFunction('I am a changed print function')
        oldPrintFunction(*args, **kwargs)

>>> print('foo')
I am a changed print function
foo