python - Python:我们真的需要装饰器的包装器吗?(重访)
问题描述
已经提出了一个类似的问题,但是 OP 将包装器与没有返回的函数进行比较,因此答案集中在那个“错误”上。阅读本文
后,我了解了装饰器以及为什么我们使用它们而不是子类。在那里,他们编写了以下示例,其中介绍了包装器的需求:
def uppercase_decorator(function):
def wrapper():
funct = function()
make_uppercase = funct.upper()
return make_uppercase
return wrapper
然而,我可以这样写“相同的东西”(我希望你说它不是):
def uppercase_decorator(function): #previously 'function' was called 'message' but 'function' is clearer for comparison.
make_uppercase = function().upper
return make_uppercase
两个版本都可以应用于这个 fn,在调用时产生相同的输出('HI ALL!')salute()
:
@uppercase_decorator
def salute():
return 'Hi all!'
如果 main fn 返回一个随机字符串(感谢@wim 的建议),人们会注意到每次运行它时,没有包装器的总是在运行该sayGarbage()
行时返回相同的内容:
def decorateIt(fn):
toUpper = fn().upper
return toUpper
def decorateW(fn):
def wrapper():
funct = fn()
toUpper = funct.upper()
return toUpper
return wrapper
import random, string
@decorateIt
def sayGarbage():
return "".join(random.choice(string.ascii_lowercase) for i in range(6))
sayGarbage()
为什么呢?
解决方案
让我们看看这里发生了什么:
def uppercase_decorator(message):
make_uppercase = func().upper
return make_uppercase
@uppercase_decorator
def salute():
return 'Hi all!'
- 首先,
uppercase_decorator
得到定义。 - 其次,
salute
得到定义。 - 第三,
uppercase_decorator
被调用,传入函数对象salute
代替第一个位置参数(message
)。
此时,代码将崩溃,因为func()
被调用并且没有在任何地方定义。如果它在您的 Python REPL 会话中有效,那么您一定在之前的func
全局范围内拥有该名称,因此代码似乎只是巧合。
我们真的需要装饰器的包装器吗?
不,可以像您建议的那样以更好的“无封闭”风格编写装饰器,但不是那样。如果您想编写一个没有嵌套函数的装饰器,请尝试使用流行的库decorator.py
。看起来像这样:
from decorator import decorator
@decorator
def uppercase_decorator(func, *args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
推荐阅读
- javascript - 防止自定义挂钩在每次重新渲染时重新初始化
- vue.js - 使用 vue-plotly 的 Vue.js 错误:fullLayout 未定义
- flutter - Flutter 应用的 ACH 支付处理(支持拆分支付)
- python - 将 Python ML 模型部署到 NodeJS Web 应用程序
- python - 当我在for中增加变量时,为什么迭代值没有发生任何事情?
- mysql - 是否有一个 mySQL 过程可以将重复的数据行合并为一个,然后允许我像处理一行一样操作该数据?
- jquery - 更改一个文本框值时使用哪个事件它应该更改 jquery 中另一个文本框中的相关值
- vb.net - 数据表中不需要的字符
- python - 从二进制矩阵构建图
- java - 使用 Java 获取终端多参数命令的输出