文件的Python上下文或无

Tho*_*ner 4 python file-handling with-statement

Python将调用一个子进程,用户要求子进程stdout将转到一个文件(或者回溯到os.devnull),或者子进程输出将通过"实时"传递.

我目前最好的猜测是如何做到这一点似乎工作:

  • 让我们file_path有效的输入open()
  • 我们logging是一个布尔指示器,真,则表示使用file_path用于记录还是假passthough到标准输出.

with open(file_path, 'wb') if logging else None as shell_stdout:
    subprocess.call(['ls'], stdout=shell_stdout)
Run Code Online (Sandbox Code Playgroud)

在修补/测试中,这似乎是正确的值,我认为它与subprocess.call配合得很好.但是,不出所料,我得到以下异常:

AttributeError: __exit__
Run Code Online (Sandbox Code Playgroud)

所以None不是一个背景,它没有__exit__;


目标

  • 如果用户不想记录,则根本不打开文件.
  • 使用上下文(由stdlib提供),(首选;我无法想象手动执行文件打开/关闭操作是否更干净.)
  • 不需要try/catch(偏好以避免进一步嵌套)
  • 只有一次调用subprocesses.call(非重复行)

那么,这种行为怎么可能实现呢?或者你会建议做什么呢?

unu*_*tbu 7

您可以创建一个"no-op" 上下文管理器:

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)
Run Code Online (Sandbox Code Playgroud)

记录时True,条件表达式返回文件对象.如果logging为False,则返回一个noop()上下文管理器(因此可以在其中使用with-statement),该设置在退出时设置shell_outNone但不执行任何特殊操作.


根据文档,何时stdout=None,

......不会发生重定向; 子项的文件句柄将从父项继承.

通常父母的标准输出会相等sys.stdout.但是,sys.stdout可以明确地(例如sys.stdout = open('/tmp/stdout', 'wb'))或间接地重定向到其他地方,例如通过使用重定向的模块sys.stdout.例如fileinput,标准库中的模块重定向sys.stdout.在这种情况下noop(),将stdout指向父级的标准输出可能很有用,这可能与标准输出不同sys.stdout.

如果这个角落的情况不会影响你,那么Padraic Cunningham的解决方案更简单:

with open(file_path, 'wb') if logging else sys.stdout as shell_stdout:
    subprocess.call(['ls'], stdout=shell_stdout)
Run Code Online (Sandbox Code Playgroud)