在Python装饰器中创建参数以供装饰函数使用

2024-10-01 09:20:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我有几个函数tempfile.mkstemp文件()创建和使用在调用函数后留在磁盘上的临时文件。它们中的每一个都重复相同的脚手架代码,以便在函数退出时清理文件描述符。例如:

import tempfile
import zipfile
import os

def write_zip(test_name: str) -> str:
    """
    Given a test name, returns an archive (ZIP) of the files in that test.
    """

    try:
        fd, zip_path = tempfile.mkstemp(suffix='.zip')

        with zipfile.ZipFile(zip_path, 'w') as zf:
            for fpath in _list_files(test_name):  # _list_files() not shown
                zf.write(fpath, arcname=os.path.basename(fpath))
    finally:
        try:
            os.close(locals()['fd'])
        except KeyError:
            pass

    return zip_path

我想把这个给装修工。我试着写了一个,但我有点迷路了,它不起作用:

def _persistent_temp_file(func):
    """
    Decorator for a function that uses a temporary file that should persist on disk after the function has exited.
    Closes the file descriptor in a try-finally block so the function doesn't have to. 
    """

    def scaffolding(suffix=None, prefix=None, dir=None, text=False):
        try:
            fd, temp_file = tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir, text=text)
            func(temp_file)

        finally:
            try:
                os.close(locals()['fd'])
            except KeyError:
                pass

    return scaffolding


@_persistent_temp_file
def write_zip(test_name: str) -> str:
    with zipfile.ZipFile(zip_path, 'w') as zf:
        for fpath in _list_files(test_name):  # _list_files() not shown
            zf.write(fpath, arcname=os.path.basename(fpath))

    return zip_path

我不确定如何将zip_file参数传递给此函数(或任何其他修饰函数)。我也不知道如何传入mkstemp()所需的参数。(即调用修饰函数时如何指定文件后缀?)你知道吗


Tags: path函数nametestosdeffileszip
1条回答
网友
1楼 · 发布于 2024-10-01 09:20:28

与其使用装饰器,不如创建一个context manager。当一个代码块(上下文)退出时,上下文管理器会被告知,这样您就可以在这时自己清理了。你知道吗

讽刺的是,有一个decorator可以让编写上下文管理器变得很容易,叫做^{}

from contextlib import contextmanager

@contextmanager
def _persistent_temp_file(suffix=None, prefix=None, dir=None, text=False):
    fd = None
    try:
        fd, temp_file = tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir, text=text)
        yield temp_file
    finally:
        if fd is not None:
            os.close(fd)

注意yield temp_file行;这是暂停此函数的点,然后temp_file值从结果上下文管理器__enter__方法返回,并可用于as子句。你知道吗

然后在with语句中使用:

def write_zip(test_name: str) -> str:
    with _persistent_temp_file() as zip_path:
        with zipfile.ZipFile(zip_path, 'w') as zf:
            for fpath in _list_files(test_name):  # _list_files() not shown
                zf.write(fpath, arcname=os.path.basename(fpath))
    return zip_path

不是说你需要在这里重新发明持久的临时文件轮。您可以在这里使用tempfile.NamedTempFile()对象:

from tempfile import NamedTempFile

def write_zip(test_name: str) -> str:
    with NamedTempFile(delete=False) as temp_file:
        with zipfile.ZipFile(temp_file, 'w') as zf:
            for fpath in _list_files(test_name):  # _list_files() not shown
                zf.write(fpath, arcname=os.path.basename(fpath))
    return temp_file.name

相关问题 更多 >