<a class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary" href="/">
模块具有几个我感兴趣的全局属性:sys
和sys.stdout
。
我正在构建自己的模块,该模块(除其他外)将sys.stderr
和sys.stdout
替换为其自己的包装器,以拦截尝试的输出,对其进行修改,然后将其转发至原件。我这样做的方法是这样的:
sys.stderr
这可以按预期的方式工作-导入模块后的任何时候,尝试对_orig_stdout = sys.stdout
_orig_stderr = sys.stderr
sys.stdout = MyFakeStdoutClass()
sys.stderr = MyFaleStderrClass()
或sys.stdout
进行的操作都会遍历我的类。
现在,我的模块对确保这种安排保持现在的状态非常感兴趣-它希望永久控制sys.stderr
和sys.stdout
。其他模块可以像我的模块一样重新分配sys.stderr
,而我的模块不希望它们能够这样做。相反,我的模块希望拦截他们的尝试。
对于常规类,这样做很容易-我只需要覆盖类的sys.stdout
方法:
__setattr__()
但是,我尝试对_orig_setattr = OtherClass.__setattr__
def my_setattr(obj, name, value):
if name != "stdout":
_orig_setattr(obj, name, value)
OtherClass.__setattr__ = my_setattr
模块本身执行此操作,但是它不起作用(即使在执行sys
之后,我仍然发现sys.__setattr__ = my_setattr
从未被调用)
此外,尽管other answers指出了为my_setattr
模块创建自己的包装器类并将其分配给sys
的可能解决方案,但这将不起作用-如果{{1 }}是在另一个模块中导入我的模块之前导入的(很可能),然后我的更改不会保留。
此外,使用一些辅助方法设置sys.modules['sys']
来返回/修改我的sys
变量也不起作用。甚至在同一文件的稍后部分,我也可以执行sys.stdout = property(stdout_getter, stdout_setter)
,它恢复了正常。我不希望这样。
有没有解决此限制的好方法?
答案 0 :(得分:1)
完全覆盖python上stdout的唯一真实方法是实际覆盖stdout文件描述符(1)。可以使用dup2
系统调用来完成。
下面是一个跨平台示例,显示了如何覆盖stdout,从而允许对写入到其中的所有数据使用自定义逻辑。在此示例中,逻辑仅复制所有写入标准输出的字符。
import os
import sys
import threading
def handle_stdout(fake_stdout, real_stdout):
while not fake_stdout.closed and not real_stdout.closed:
char = fake_stdout.read(1)
real_stdout.write(char * 2)
def override_stdout():
stdout_fd = 1
pipe_reader_fd, pipe_writer_fd = os.pipe()
pipe_reader = os.fdopen(pipe_reader_fd, 'r')
original_stdout_writer = os.fdopen(os.dup(stdout_fd), 'w')
os.dup2(pipe_writer_fd, stdout_fd)
return pipe_reader, original_stdout_writer
# Override stdout
pipe_reader, original_stdout_writer = override_stdout()
thread = threading.Thread(target=handle_stdout, args=(pipe_reader, original_stdout_writer))
thread.start()
# Write stuff to stdout
print('foobar')
# Cleanup to allow background thread to shut down
pipe_reader.close()
original_stdout_writer.close()
运行此示例将输出:
ffoooobbaarr
对于某些版本的python,您必须将PYTHONLEGACYWINDOWSSTDIO
环境变量设置为非空字符串才能使该示例在Windows上运行。