我正在使用上下文管理器来包装将在终端中显示并同时写入文件的文本。
我遇到了这个问题并得到了解决方案,请检查 Writing terminal output to terminal and to a file?
无法更改功能(等func1和func2)问题是在'之后用'声明任何输出为sys.stdout.write其显示值错误:关闭文件中的I / O操作
示例代码:
import sys, datetime
class FileWrite(object):
def __init__(self,log_file_name, stdout):
self.log_file_name = log_file_name
self.stdout = stdout
def __enter__(self):
self.log_file = open(self.log_file_name, 'a', 0)
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
self.log_file.close()
def write(self, data):
self.log_file.write(data)
self.stdout.write(data)
self.stdout.flush()
def func1():
sys.stdout.write('A')
def func2():
sys.stdout.write('B')
def main():
with FileWrite(..........., sys.stdout) as sys.stdout:
func1()
func2()
sys.stdout.write('test')
main()
............................
# both output A and B is showing in terminal and writing in file
............................
# writing 'test' only in terminal......
I/O operation in closed file
答案 0 :(得分:2)
你真的不需要(或想要)在这里使用as
。如果目标是将对sys.stdout
的任何写入转换为对sys.stdout
和您的日志文件的写入,则需要在sys.stdout
上备份__enter__
并在{{1}上将其恢复1}},但是没有明确地将__exit__
传递给构造函数,并且不使用sys.stdout
返回来替换__enter__
,因为它会绕过sys.stdout
/ { {1}}代码。相反,让__enter__
和__exit__
替换您的工作:
__enter__
现在,用法只是:
__exit__
注意:如果你的目标是Python 3.4或更高版本,我建议只使用class tee_stdout(object):
def __init__(self, log_file_name):
self.log_file_name = log_file_name
self.stdout = None
def __enter__(self):
self.log_file = open(self.log_file_name, 'a', 0)
# Replace sys.stdout while backing it up
self.stdout, sys.stdout = sys.stdout, self
def __exit__(self, exc_type, exc_value, exc_traceback):
sys.stdout = self.stdout # Restore original sys.stdout
self.log_file.close()
def write(self, data):
self.log_file.write(data)
self.stdout.write(data)
self.stdout.flush()
实现该类,然后使用 with tee_stdout(logfilename):
... do stuff that uses sys.stdout, explicitly or implicitly ...
... when block exits, sys.stdout restored, so normal behavior resumes ...
来避免重新发明轮子:
write
注意:除了以上所述之外,通常,您只想使用the logging
module和记录器方法来处理这样的事情。您可以预先配置不同的记录器,一些转到contextlib.redirect_stdout
,一些转到日志文件和from contextlib import redirect_stdout
class tee_output:
def __init__(self, *targets):
self.targets = targets
def write(self, data):
for tgt in self.targets:
tgt.write(data)
tgt.flush()
with open(logfilename, 'a') as log, redirect_stdout(tee_output(log, sys.stdout)):
... logs to logfilename and sys.stdout when sys.stdout written to ...
... undoes redirection ...
,一些只记录日志文件,并在需要时使用适当的记录器。
答案 1 :(得分:1)
with FileWrite(..........., sys.stdout) as sys.stdout:
您正在覆盖sys.stdout
,只为您的文件选择了一个真实姓名,例如output
或sys.stdout
以外的其他文件。
示例:
with FileWrite(..........., sys.stdout) as output:
output.write('A')
output.write('B')
sys.stdout.write("test")
修改强>
由于您并不真的想在标准输出上书写,请将FileWrite
实例作为参数传递给您的方法。
def func1(output):
output.write('A')
with FileWrite(..........., sys.stdout) as output:
func1(output)
对func2执行相同的操作。