Python 将调用一个子进程,用户要么请求子进程 stdout 转到一个文件(或返回到 os.devnull),要么子进程输出将“实时”传递。
我目前最好的猜测是如何做到这一点似乎可行:
- 让
file_path
成为open()
的有效输入 - 设
logging
为 bool 指示符,true 表示使用file_path
进行日志记录,false 表示直通到 stdout。
with open(file_path, 'wb') if logging else None as shell_stdout:
subprocess.call(['ls'], stdout=shell_stdout)
在修补/测试中,这似乎是正确的值,我假设它与 subprocess.call 一起工作。但是,毫不奇怪,我得到以下异常:
AttributeError: __exit__
所以None
不是上下文,它没有__exit__
;
目标
- 如果用户不想记录,则根本不打开文件。
- 使用上下文(由 stdlib 提供),(首选项;我无法想象手动执行文件打开/关闭操作会更干净。)
- 不需要 try/catch(避免进一步嵌套的偏好)
- 只调用一次
subprocesses.call
(非重复行)
那么,如何实现这种行为呢?或者你会建议做什么来代替/替代?
最佳答案
您可以创建一个“无操作”context manager :
import subprocess
import contextlib
@contextlib.contextmanager
def noop():
yield None
logging = False
file_path = '/tmp/out'
with open(file_path, 'wb') if logging else noop() as shell_stdout:
subprocess.call(['ls'], stdout=shell_stdout)
当 logging 为 True
时,条件表达式返回一个文件对象。当 logging
为 False 时,它返回一个 noop()
上下文管理器(因此它可以在 with-statement
中使用),它设置 shell_out
到 None
但在退出时不执行任何特殊操作。
Per the docs , 当 stdout=None
,
... no redirection will occur; the child’s file handles will be inherited from the parent.
通常父级的标准输出等于 sys.stdout
。但是,可以将 sys.stdout
重定向到其他地方,无论是显式(例如 sys.stdout = open('/tmp/stdout', 'wb')
)还是间接地,例如通过使用重定向 sys.stdout
的模块。例如,标准库中的 fileinput
模块重定向 sys.stdout
。在这种情况下,noop()
可能有助于将 stdout 定向到父级的 stdout,这可能与 sys.stdout
不同。
如果这个角落案例不影响你,那么Padraic Cunningham's solution更简单:
with open(file_path, 'wb') if logging else sys.stdout as shell_stdout:
subprocess.call(['ls'], stdout=shell_stdout)
关于文件或无的 Python 上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28680442/