我正在处理一个来自MOOC的数据集。我有很多Python3代码片段需要运行并获取结果。为此,我编写了一个Python脚本来循环执行每个代码片段。对于每个代码片段,我会:
为了处理这种情况,我一直在尝试使用
所以我的问题是:如何重定向或捕获进程的 stdout/stderr?另外,有什么其他方法可以尝试运行和捕获任意代码的输出?
(是的,我知道这一般来说是个坏主意;我是在虚拟机中运行它,以防万一里面有恶意代码)
Python 版本为 3.5.3
更新
我意识到在这种情况下还有一些小小的灵活性。我有一个函数,
以下是一个示例实现:
我可以使用预处理函数帮助重定向STDOUT。
- 创建新的StringIO对象
- 将
sys.stdout
和sys.stderr
设置为我的StringIO缓冲区 - 在
threading.thread
对象中执行代码片段 - 等待线程结束
- 将结果记录在StringIO缓冲区中
- 恢复stdout和stderr
- 当代码有无限循环时,thread.join不能杀死线程。由于该线程是守护进程,因此它会在后台静默运行,直到我的循环完成。
- 当代码有一个带有
print()
的无限循环时,当我将它从StringIO缓冲区切换回默认值(即不从StringIO缓冲区输出)时,该线程开始覆盖我的实际stdout。这会污染我的报告。
def execCode(code, testScript=None):
# create file-like string to capture output
codeOut = io.StringIO()
codeErr = io.StringIO()
# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr
def worker():
exec(code, globals())
if testScript:
# flush stdout/stderror
sys.stdout.truncate(0)
sys.stdout.seek(0)
# sys.stderr.truncate(0)
# sys.stderr.seek(0)
exec(testScript)
thread = threading.Thread(target=worker, daemon=True)
# thread = Process(target=worker) #, stdout=codeOut, stderr=codeErr)
thread.start()
thread.join(0.5) # 500ms
execError = codeErr.getvalue().strip()
execOutput = codeOut.getvalue().strip()
if thread.is_alive():
thread.terminate()
execError = "TimeError: run time exceeded"
codeOut.close()
codeErr.close()
# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
# restore any overridden functions
restoreBuiltinFunctions()
if execError:
return False, stripOuterException(execError)
else:
return True, execOutput
为了处理这种情况,我一直在尝试使用
multithreading.Process
和/或 contextlib.redirect_stdout
在进程中运行代码(然后我可以调用 process.terminate()
),但是我没有成功捕获 stdout/stderr。所以我的问题是:如何重定向或捕获进程的 stdout/stderr?另外,有什么其他方法可以尝试运行和捕获任意代码的输出?
(是的,我知道这一般来说是个坏主意;我是在虚拟机中运行它,以防万一里面有恶意代码)
Python 版本为 3.5.3
更新
我意识到在这种情况下还有一些小小的灵活性。我有一个函数,
preprocess(code)
接受代码提交作为字符串并对其进行更改。大多数情况下,我一直在使用正则表达式交换某些变量的值。以下是一个示例实现:
def preprocess(code):
import re
rx = re.compile('earlier_date\s*=\s*.+')
code = re.sub(rx, "earlier_date = date(2016, 5, 3)", code)
rx = re.compile('later_date\s*=\s*.+')
code = re.sub(rx, "later_date = date(2016, 5, 24)", code)
return code
我可以使用预处理函数帮助重定向STDOUT。
subprocess.check_output
怎么样?你可以使用它来调用python -c {snippet}
,或者如果代码比较长,可以将代码片段写入临时的.py
文件中。check_output
(以及subprocess
中的所有其他函数)都有一个timeout
参数。 - David Nemeskey