python - 使用装饰器

标签 python decorator

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

请让我知道它是否可以更像 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 !!!")

我应该关闭文件吗?怎么办?

最佳答案

如果您知道只想在装饰函数中使用该文件,那么最好使用 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 个参数重要 - 不应使用其自己的参数调用。

关于python - 使用装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11589444/

相关文章:

python - 缺少 'webapp2_extras.sessions' 的配置键 : ['secret_key' ]

python - 用 Python 抓取网站的第二页不起作用

c# - Autofac 修饰使用程序集扫描注册的开放泛型

python - 在不下载正文的情况下检查 Python 中的 HTTP POST header

python - Scipy - 找到矩阵列空间的基础

python - Python 装饰器的参数

C++ 装饰器模式

design-patterns - 策略模式 VS 装饰模式

python - 如何使用 Flask_login.login_required 装饰器客户端

java - 在 Java 中复制复杂的数据结构