我想知道是否可以覆盖内置函数print
,以便以下语句同时写入控制台和文件。
print("test0","test1","test2",sep='\n')
另外,我是否可以知道是否可以修改内置print
功能的源代码?
答案 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_func
和return 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