在Python中使用子进程的上下文管理器的简单解释是什么?

时间:2014-06-10 03:34:49

标签: python

我是一个活跃的python用户,似乎互联网上的大多数教程都指向一个带有子进程的上下文管理器来处理通过python执行二进制文件,例如使用exiftool读取图像exif数据。

def readExif(fname):
    with ExifTool() as e:
        try:
            metadata = e.get_metadata(fname)
            metadata = metadata[0]
        except UnicodeDecodeError:
             return False

for f in files:
    print readExif(f)

这是我的问题(从真正的初学者的角度来看):为什么我不能使用os.system()?

2 个答案:

答案 0 :(得分:2)

ExifTool装饰器只是删除了很多很多的样板和错误处理,你需要使用像os.system()之类的东西直接调用exiftool可执行文件。即使您直接使用subprocess.Popen,这比os.system更高级,您的代码看起来与ExifTool提供的内容相同:

with open(os.devnull, "w") as devnull:
    _process = subprocess.Popen(
        [self.executable, "-stay_open", "True",  "-@", "-",
         "-common_args", "-G", "-n"],
         stdin=subprocess.PIPE, stdout=subprocess.PIPE,
        stderr=devnull)
try:
    _process.stdin.write(b"\n".join([filename] + (b"-execute\n",)))
    _process.stdin.flush()
    output = b""
    fd = _process.stdout.fileno()
    sentinel = b"{ready}"
    while not output[-32:].strip().endswith(sentinel):
       output += os.read(fd, block_size)
    metadata = output.strip()[:-len(sentinel)][0]
    metadata = metdata[0]
except UnicodeDecodeError:
    return False
finally:
    _process.stdin.write(b"-stay_open\nFalse\n")
    _process.stdin.flush()
    _process.communicate()
    del _process

(这是完全未经测试的,可能不会起作用。我只是快速查看了source的pyexiftool将它们放在一起。)

正如你所看到的那样,那里有很多东西。上下文管理器本身处理try块之前的所有内容以及整个finally块。如果您想使用ExifTool而不使用它作为上下文管理器,但具有相同的功能,它将如下所示:

e = ExifTool()
e.start()
try:
    metadata = e.get_metadata(fname)
    metadata = metadata[0]
except UnicodeDecodeError:
    return False
finally:
    e.terminate()

您可以通过查看ExifTool.__enter__()ExifTool.__exit__()来确认这一点,这两种方法分别在您进入和退出with ExifTool() as e:块时被调用。

肯定有很多简单的情况,直接执行带有os.system的子进程可以正常工作(尽管一般情况下我建议使用subprocess模块)。然而,您一直在寻找的特定示例恰好要复杂得多,并且受益于面向对象编程和上下文管理器提供的抽象。

答案 1 :(得分:0)

这取决于您在子进程中要完成的任务。 os.system()适用于执行不需要与之交互的内容,但通常需要或希望能够读取stdout / stderr并与主进程并行运行子进程。使用上下文管理器更加灵活,能够处理简单子命令执行之外的所有事情。