【发布时间】:2018-03-13 03:48:41
【问题描述】:
我需要能够在线程上下文中捕获函数的返回值及其stdout/stderr。目前,我正在通过在每个子类中调用is_true 方法来评估基于此基类(my_base_class)的许多子类(my_class_foo、my_class_bar)。
我希望能够同时捕获每个 is_true 以及 stdout/stderr 的返回值。下面的当前解决方案适用于非线程或非多进程上下文。但是,它依赖于重定向 stdout/stderr,如果我同时评估多个子类,这显然是行不通的。
我查看了 concurrent.futures 和 multiprocess 和 subprocess 包,但找不到解决方案。
我试图避免使用记录器,以便用户可以只依赖打印到stdout 而不是使用显式方法。
我想并行执行my_class_foo 和my_class_bar 中的is_true 方法,并能够使用每个类的返回值捕获stdout 消息。
class my_class_foo(my_base_class):
def is_true(self):
print('foo')
return True
class my_class_bar(my_base_class):
def is_true(self):
print('bar')
return False
class my_base_class(object):
def is_true(self):
Raise NotImplementedError
def evaluate_node_is_true(self):
with Capturing() as is_true_stdout:
node_is_true = self.is_true()
self.output = ''.join(is_true_stdout)
class Capturing(list):
"""
Context manager for capturing the stdout of the is_true() function call
"""
def __enter__(self):
self._stdout = sys.stdout
self._stderr = sys.stderr
sys.stdout = self._stringio_out = io.StringIO()
sys.stderr = self._stringio_err = io.StringIO()
return self
def __exit__(self, *args):
self.extend(self._stringio_out.getvalue().splitlines())
self.extend(self._stringio_err.getvalue().splitlines())
del self._stringio_out
del self._stringio_err
sys.stdout = self._stdout
sys.stderr = self._stderr
【问题讨论】:
-
这必须与线程一起使用,还是只能与进程一起使用?因为后者要容易得多。
-
另外:“我查看了 concurrent.futures 以及多进程和子进程包……”您尝试了什么?使用捕获的 stdio 在
sys.executable上触发subprocess.run非常简单,我不明白为什么它对你不起作用。 -
顺便说一句,一旦
stdout和朋友与子解释器正确绑定在一起,就可以将它们包装在 PEP 567 上下文变量中。不要屏住呼吸——它可能发生的最早可能是 3.9,即使他们决定这样做——但这显然会使这个问题变得容易得多。 -
如果我可以让它与流程一起工作,那么我会很满意。进程的问题是我不知道如何在下面的答案中获取 sys.executable 的返回值。有没有办法做到这一点?提前致谢。
-
嗯,一个子进程除了一个 8 位整数之外不能返回任何东西,所以你需要找到一些其他的方法来传递它——在标准输出中的一个特殊的最后一行,或者你需要的管道作为额外的 fd 等传递下去。
标签: python multithreading function return stdout