[英]Creating parameters in a Python decorator for use by the decorated function
I have several functions that use tempfile.mkstemp() to create and use temporary files that stay on disk after the function has been called. 我有几个使用tempfile.mkstemp()的函数来创建和使用在函数被调用后保留在磁盘上的临时文件。 Each of them repeats the same scaffolding code to clean up the file descriptor when the function exits.
当函数退出时,它们每个都重复相同的脚手架代码以清理文件描述符。 For example:
例如:
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
I'd like to pull this try-finally scaffolding out to a decorator. 我想把这个最终尝试的脚手架拉到一个装饰器上。 I tried writing one, but I'm a bit lost and it isn't working:
我尝试写一个,但是我有点迷茫,它不起作用:
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
I'm unsure of how to pass the zip_file
parameter to this function (or any other decorated function). 我不确定如何将
zip_file
参数传递给此函数(或任何其他装饰函数)。 I'm not sure I know how to pass in the parameters needed by mkstemp(), either. 我不确定我也不知道如何传递mkstemp()所需的参数。 (ie How do I specify the file suffix when calling the decorated function?)
(即调用装饰函数时如何指定文件后缀?)
Rather than use a decorator, you'd want to create a context manager . 您想要创建一个上下文管理器,而不是使用装饰器 。 A context manager is told when a block of code (the context) exits, so you can clean up after yourself at that point.
当代码块(上下文)退出时,将通知上下文管理器,因此您可以在此之后自行清理。
Ironically, there is a decorator that makes it easy to write a context manager, called @contextlib.contextmanager
: 具有讽刺意味的是,有一个装饰器可以轻松地编写上下文管理器,称为
@contextlib.contextmanager
:
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)
Note the yield temp_file
line; 注意
yield temp_file
行; that's the point at which this function is paused, and the temp_file
value is then returned from the resulting context manager __enter__
method, and becomes available to the as
clause. 这是在其中该功能被暂停的点,并且
temp_file
值然后从所得的上下文管理器返回__enter__
方法,并且变得可用于as
子句。
Then use this in a with
statement: 然后在
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
Not that you need to re-invent the persistent-temp-file wheel here. 并不是说您需要在这里重新发明持久性临时文件轮。 You could just use the
tempfile.NamedTempFile()
object here instead: 您可以只在这里使用
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.