如何重载打印功能以扩展其功能?

时间:2014-12-23 13:46:59

标签: python python-3.x overloading

我想知道是否可以覆盖内置函数print,以便以下语句同时写入控制台和文件。

print("test0","test1","test2",sep='\n') 

另外,我是否可以知道是否可以修改内置print功能的源代码?

4 个答案:

答案 0 :(得分:6)

您可以使用write方法创建一个类,并且在该方法内,print stdout以及文件write

import sys

class A(object):
    def __init__(self, f):
        self.f = open(f, 'w') 

    def __enter__(self):
        return self   # return instance of A which is assign to `f`.

    def write(self, text):
        sys.stdout.write(text)  # print to the shell
        self.f.write(text) # write in the file

    def __exit__(self, *args):
        self.f.close()
        return True

with A('foo.txt') as f:
    print("test0","test1","test4",sep='\n', file=f) #`file = f` calls `write` method

答案 1 :(得分:3)

使用装饰器。简化示例:

def my_decorator(func):
    def wrapped_func(*args,**kwargs):
        return func("I've been decorated!",*args,**kwargs)
    return wrapped_func

print = my_decorator(print)

测试:

print("TESTING") #I've been decorated! TESTING

所以要在同一时间打印到文件:

def super_print(filename):
    '''filename is the file where output will be written'''
    def wrap(func):
        '''func is the function you are "overriding", i.e. wrapping'''
        def wrapped_func(*args,**kwargs):
            '''*args and **kwargs are the arguments supplied 
            to the overridden function'''
            #use with statement to open, write to, and close the file safely
            with open(filename,'a') as outputfile:
                outputfile.write(*args,**kwargs)
            #now original function executed with its arguments as normal
            return func(*args,**kwargs)
        return wrapped_func
    return wrap

print = super_print('output.txt')(print)

如果将此与上面的示例进行比较,您会发现在这种情况下还有一个额外的闭包(即return wrapped_funcreturn wrap,而不仅仅是return wrapped_func。第二个闭包允许我们向包装器/装饰器函数发送一个额外的参数(filename)。

这最后一行的语法看起来有点奇怪,但这是正确的方法。对super_print('output.txt')的调用返回一个对象,然后将该print函数对象作为附加参数。这一切都是通过封闭来实现的;如果你没有达到速度,请研究它们。

然后:

print('test')

test将写入控制台输出和output.txt。

答案 2 :(得分:1)

print函数使用sys.stdout,除非给出明确的file参数。

您可以将sys.stdout重定向到同时写入控制台和文件的类文件对象:

#!/usr/bin/env python3
import sys
from contextlib import redirect_stdout

class TeeFile: # write to multiple files at once
    def __init__(self, *files):
        self.files = files
    def write(self, data):
        for file in self.files:
            file.write(data)
    def flush(self):
        for file in self.files:
            file.flush()

with open('log', 'a') as log, redirect_stdout(TeeFile(log, sys.stdout)):
    print("test0", "test1", "test2", sep='\n')

redirect_stdout在Python 3.4中引入,但是it is easy to implement it on earlier versions

如果要全局替换builtins.print函数,可以替换print函数。 在您的情况下,考虑logging模块是否提供了比print函数更好的解决方案。

答案 3 :(得分:1)

这个答案可能有点晚了,但是我已经创建了一个包(https://github.com/phohenecker/stream-to-logger),它提供了你正在寻找的东西,即将stdout + stderr重定向到一个文件(除了通常的屏幕打印之外)。

这非常简单,您只需在代码中添加两行:

import streamtologger
streamtologger.redirect(target="./all-output.log")

您可以使用pip安装软件包:

pip install git+https://github.com/phohenecker/stream-to-logger