上下文管理器文件中的I / O操作

时间:2016-10-05 00:12:25

标签: python

我正在使用上下文管理器来包装将在终端中显示并同时写入文件的文本。

我遇到了这个问题并得到了解决方案,请检查 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

2 个答案:

答案 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,只为您的文件选择了一个真实姓名,例如outputsys.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执行相同的操作。