4

我想构建不同的函数,其中每个函数都必须使用文件。我已经用装饰器实现了这个。

请让我知道它是否可以更pythonic:

def open_file(func):
    def a_wrapper(filename,separator,*args):
        f = open(filename,'w')
        return func(f,separator,*args)
    return a_wrapper

@open_file
def write_multiple_items(file, sep, *args):
    file.write(sep.join(args))

@open_file
def write_one_item(file,sep,name):
    file.write(sep.join(name))

write_multiple_items('foo.txt','--',"Hello","World", "!!!!")
write_one_item('bar.txt','--',"Bye World !!!")

我应该关闭文件吗?如何?

4

2 回答 2

4

with如果您知道您只想在您的装饰函数中使用该文件,那么最好使用一个语句。另外,separator是一个实现细节 - 我会把它放在包装器之外:

def open_file(func):
    def a_wrapper(filename, *args):
        with open(filename, 'w') as f:
            return func(f, *args)
    return a_wrapper

此外,正如@Platinum Azure 所指出的,使用functools.wraps装饰器函数总是一个好主意 - 这将确保包装函数的元数据存在于包装函数中(当您希望能够区分您的以编程方式包装函数)。

编辑:

您应该移出separator包装函数的原因是因为您可能有其他函数只需要获取文件对象并且不需要分隔符。如果您创建这样的函数:

def say_hello(fp):
    fp.write("Hello World!")

不能使用open_file也尝试传入的装饰器separator版本say_hello- 尝试它会得到一个TypeError,因为您试图调用一个函数,该函数接受一个参数(一个文件对象)和两个参数 - 一个文件对象和一个分隔器。

此外,即使您的所有包装函数都至少需要一个额外的参数,它也不必分隔符。即使使用未经编辑的装饰器,这也是一个合法的包装功能:

def laugh(fp, number_of_times):
    fp.write("Ha! " * number_of_times)

这就是我所说separator的实现细节的意思。理想情况下,您的代码也是文档。如果您只使用此包装器来写出除以分隔符的数据,那么您应该将分隔符参数留在包装器中,因为它有助于记录应该如何使用包装器。否则,第二个参数并不比第 14 个更重要——并且不应该用它自己的参数来调用。

于 2012-07-21T04:35:20.233 回答
3

您可以在包装函数中使用try/finally来确保文件已关闭,或者with如果您使用的是足够新的 Python 版本,则可以使用该语句。

from functools import wraps
def open_file(func):
    @wraps(func)
    def a_wrapper(filename, sep, *args):
        f = open(filename, 'w')
        try:
            return func(f, sep, *args)
        finally:
            f.close()
    return a_wrapper

使用with

from functools import wraps
def open_file(func):
    @wraps(func)
    def a_wrapper(filename, sep, *args):
        with open(filename, 'w') as f:
            return func(f, sep, *args)
    return a_wrapper
于 2012-07-21T04:34:32.293 回答