在Python中显示exec的当前输出
我运行的代码如下(是从其他话题复制过来的,并加了sleep
):
import sys
import StringIO
import contextlib
@contextlib.contextmanager
def stdoutIO(stdout=None):
old = sys.stdout
if stdout is None:
stdout = StringIO.StringIO()
sys.stdout = stdout
yield stdout
sys.stdout = old
code = """
import time
i = [0,1,2]
for j in i :
print j
time.sleep(5)
"""
with stdoutIO() as s:
exec code
print "out:", s.getvalue()
当我运行这段代码时,我得等15秒,程序才结束才能看到输出。可是我想要在每次循环的每5秒就能看到print
语句的输出,而不是等15秒才能看到全部的输出。
这有可能吗?能不能实时看到执行的当前输出呢?
2 个回答
1
这个问题和exec没有关系。问题在于你把标准输出(stdout)重定向到了一个StringIO
对象。所有的打印语句都在往这个StringIO
里添加内容,而不是直接打印到屏幕上。所以你看不到任何输出。唯一一行能在屏幕上打印内容的是
print "out:", s.getvalue()
这行代码是在15秒的睡眠之后执行的。
with stdoutIO() as s:
...
这段代码把stdout
重定向到了StringIO.StringIO
。只有在with
上下文结束后,stdout
才会被重定向回原来的sys.stdout
,这样才能在终端上打印出来。
所以,如果你想在执行时看到print语句的输出,只需去掉stdeoutIO
的上下文管理器:
import sys
code = """
import time
i = [0,1,2]
for j in i :
print j
time.sleep(5)
"""
exec code
1
在你发的代码中,使用的上下文管理器在执行 with
的时候只会运行一次。所以,代码必须先执行完(总共15秒),然后所有的输出结果都会存储在 StringIO
这个对象里。因此,使用这样的代码,你 无法 实时获取输出。
如果你想要实时输出,你需要提供一个自己的类似 file
的类,而不是使用 StringIO
,并且重写 write
方法。比如(这个例子只是个简单粗糙的代码):
import sys
import StringIO
import contextlib
class Proxy(object):
def __init__(self,stdout,stringio):
self._stdout = stdout
self._stringio = stringio
def __getattr__(self,name):
if name in ('_stdout','_stringio','write'):
object.__getattribute__(self,name)
else:
return getattr(self._stringio,name)
def write(self,data):
self._stdout.write(data)
self._stringio.write(data)
@contextlib.contextmanager
def stdoutIO(stdout=None):
old = sys.stdout
if stdout is None:
stdout = StringIO.StringIO()
sys.stdout = Proxy(sys.stdout,stdout)
yield sys.stdout
sys.stdout = old
code = """
import time
i = [0,1,2]
for j in i :
print j
time.sleep(5)
"""
with stdoutIO() as s:
exec code
print "out:", s.getvalue()
这个代码的输出是:
0
1
2
out: 0
1
2
前面三行每隔5秒打印一次,最后三行则是在结束时一次性打印出来。