文件的Python上下文或无

时间:2015-02-23 18:12:06

标签: python file-handling with-statement

Python将调用子进程,用户要么子进程stdout要转到文件(或者回溯到os.devnull),要么子进程输出通过"实际时间"

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

  • file_path成为open()
  • 的有效输入
  • logging成为布尔指示符,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(非重复行)

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

3 个答案:

答案 0 :(得分:7)

你可以创建一个" no-op" 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)

当记录为True时,条件表达式返回一个文件对象。当logging为False时,它会返回noop()上下文管理器(因此可以在with-statement中使用),这会将shell_out设置为None但不会# 39;退出时做任何特别的事。


Per the docsstdout=None时,

  

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

通常父母的标准输出将等于sys.stdout。但是,可以明确地(例如sys.stdout)或间接地将sys.stdout = open('/tmp/stdout', 'wb')重定向到其他位置,例如通过使用重定向sys.stdout的模块。例如,标准库中的fileinput模块会重定向sys.stdout。在这种情况下,noop()可能有助于将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)

答案 1 :(得分:3)

根据记录为True或False,将shell_stdout设置为stdoutfile object,无需过度复杂化,只有一个条件或另一个{{1无论是True还是False,打开不使用if logging的文件都没有错,有时使用with不合适。

with

要在您的问题中执行您想要的操作,您可以执行以下操作,您不需要任何条形import sys if logging: shell_stdout = open(file_path, 'wb') # to file or devnull if logging else: shell_stdout = sys.stdout subprocess.call(['ls'], stdout=shell_stdout) # real time if not logging shell_stdout.close()

sys.stdout

只有在记录为True时才会创建文件。

答案 2 :(得分:0)

从Python 3.3开始,tou可以使用contextlib.ExitStack定义一个无操作的上下文管理器:

from contextlib import ExitStack

with open(...) if ... else ExitStack():
    ...