将NamedTemporaryFile传递给Windows上的子进程

Eri*_*ric 5 python temporary-files

为python文档tempfile.NamedTemporaryFile说:

名称是否可以用于第二次打开文件,而命名的临时文件仍然是打开的,因此不同平台(它可以在Unix上使用;它不能在Windows NT或更高版本上使用).

我有一个被调用的程序,prog input.txt我无法触及.我想写一个python函数来给它一个字符串.

这里的各种方法并不常用:

from tempfile import NamedTemporaryFile
Run Code Online (Sandbox Code Playgroud)
  1. 如果在Windows上合法,则不明显

    with NamedTemporaryFile() as f:
        f.write(contents)
        subprocess.check_call(['prog', f.name])  # legal on windows?
    
    Run Code Online (Sandbox Code Playgroud)
  2. 可能会过早删除文件

    with NamedTemporaryFile() as f:
        f.write(contents)
        f.close()  # does this delete the file?
        subprocess.check_call(['prog', f.name])
    
    Run Code Online (Sandbox Code Playgroud)
  3. 不能正常清理

    with NamedTemporaryFile(delete=False) as f:
        f.write(contents)  # if this fails, we never clean up!
    try:
        subprocess.check_call(['prog', f.name])
    finally:
        os.unlink(f.name)
    
    Run Code Online (Sandbox Code Playgroud)
  4. 有点难看

    f = NamedTemporaryFile(delete=False)
    try:
        with f:
            f.write(contents)
        subprocess.check_call(['prog', f.name])
    finally:
        os.unlink(f.name)
    
    Run Code Online (Sandbox Code Playgroud)

哪一项是正确的?

Ara*_*Fey 1

正如您所怀疑的,前三个变体都已损坏 - 第一个变体PermissionError在 Windows 上会抛出 a ;第二个确实太早删除了文件;第三个不能正确处理异常。

因此,您的第四个片段是正确的方法。


不过,正如你所说,它有点难看。我建议将其包装在一个函数中以提高可读性和可重用性:

import os
from contextlib import contextmanager
from tempfile import NamedTemporaryFile

@contextmanager
def ClosedNamedTempfile(contents, mode='w'):
    f = NamedTemporaryFile(delete=False, mode=mode)
    try:
        with f:
            f.write(contents)
        yield f.name
    finally:
        os.unlink(f.name)
Run Code Online (Sandbox Code Playgroud)

这允许我们像这样使用它:

with ClosedNamedTempfile('foobar\n') as f:
    subprocess.check_call(['prog', f])
Run Code Online (Sandbox Code Playgroud)