如何在Python中子类化文件类型?
我正在尝试在Python中对内置的file
类进行子类化,以便为stdin
和stdout
添加一些额外的功能。以下是我目前的代码:
class TeeWithTimestamp(file):
"""
Class used to tee the output of a stream (such as stdout or stderr) into
another stream, and to add a timestamp to each message printed.
"""
def __init__(self, file1, file2):
"""Initializes the TeeWithTimestamp"""
self.file1 = file1
self.file2 = file2
self.at_start_of_line = True
def write(self, text):
"""Writes text to both files, prefixed with a timestamp"""
if len(text):
# Add timestamp if at the start of a line; also add [STDERR]
# for stderr
if self.at_start_of_line:
now = datetime.datetime.now()
prefix = now.strftime('[%H:%M:%S] ')
if self.file1 == sys.__stderr__:
prefix += '[STDERR] '
text = prefix + text
self.file1.write(text)
self.file2.write(text)
self.at_start_of_line = (text[-1] == '\n')
我的目的是在每条消息的开头添加一个时间戳,并将所有内容记录到一个日志文件中。不过,我遇到的问题是,如果我这样做:
# log_file has already been opened
sys.stdout = TeeWithTimestamp(sys.stdout, log_file)
那么当我尝试执行print 'foo'
时,就会出现ValueError: I/O operation on closed file
的错误。我无法在我的__init__()
方法中有意义地调用file.__init__()
,因为我不想打开一个新文件,而且我也不能将self.closed = False
,因为这是一个只读属性。
我该如何修改这个代码,以便我可以执行print 'foo'
,并且支持所有标准的file
属性和方法呢?
2 个回答
3
你也可以不使用 super
:
class SuperFile(file):
def __init__(self, *args, **kwargs):
file.__init__(self, *args, **kwargs)
这样你就能顺利写代码了。
12
调用 file.__init__
是可行的(比如在 '/dev/null' 上),但实际上没有什么用,因为你尝试重写的 write
方法对 print
语句来说并没有效果——因为 print
内部会直接调用真正的 file.write
,当它发现 sys.stdout
是一个真正的 file
实例时(而你通过继承让它变成了这样)。
print
其实只需要 write
这个方法,所以如果你的类继承自 object
而不是 file
,也是可以正常工作的。
如果你需要其他文件的方法(也就是说,print
不是你唯一要做的事情),那么最好自己实现这些方法。