我正在使用Python 3.4进行工作,遇到了一个我不理解的问题:如果我将stdout重定向到文件,我可以捕获子进程的文本。但是,当我将其重定向到Python文件对象时,我停止捕获该输出。我希望能够解释一下这种行为。
我的代码如下:
from multiprocessing import Process
def worker():
print('forked output')
def output():
print('redirected')
p = Process(target=worker)
p.daemon = True
p.start()
p.join() # wait for subprocess to terminate
print('end')
在Python 3.4中,
redirect_stdout
上下文管理器使得获取stdout变得容易(在这种情况下)。from contextlib import redirect_stdout
from sys import stdout
from tempfile import TemporaryFile
with TemporaryFile(mode='w+', encoding=stdout.encoding) as buf:
with redirect_stdout(buf):
output() # the function defined above
buf.seek(0)
s = buf.read()
print('output from TemporaryFile:')
print(s)
我可以简单地调用脚本,以获取以下输出:
$ python stackoverflow.py
output from TemporaryFile:
redirected
forked output
end
这正是我想要的,而且运行良好。
我的困惑在于,如果我将TemporaryFile
替换为TextIOWrapper
,那么我的脚本的行为会改变。
from io import BytesIO, TextIOWrapper
with TextIOWrapper(BytesIO(), stdout.encoding) as buf:
with redirect_stdout(buf):
output() # the function defined at the start
buf.seek(0)
s = buf.read()
print('output from TextIO:')
print(s)
现在当我调用程序时,我失去了分叉进程的输出。
$ python stackoverflow.py
output from TextIO:
redirected
end
发生了什么事情?
我怀疑问题与 TextIOWrapper
对象没有文件描述符有关,而 multiprocessing
使用的 os.fork()
可能正在用另一个替换 TextIOWrapper
,但我承认有些困惑(特别是考虑到标准输出似乎是带有实现 fileno()
的 TextIOWrapper
)。
>>> from sys import stdout
>>> stdout.fileno()
1
>>> stdout
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
谢谢提供的信息。
stdout
、stderr
或stdin
是操作系统级别的操作,而不是 Python 操作。它适用于文件描述符。BytesIO
对象没有文件描述符,因为它严格来说是内存中的字节 blob。TemporaryFile
是可行的方法。在 Linux 上,如果您将文件创建在目录/dev/shm
中,它永远不会实际上命中磁盘驱动器(尽管,可以说,使用/tmp
也没有)。 - eestrada