python - 如何装饰可调用类的实例?

标签 python decorator

def decorator(fn):
    def wrapper(*args, **kwargs):
        print 'With sour cream and chives!',
        return fn(*args, **kwargs)
    return wrapper

class Potato(object):
    def __call__(self):
        print 'Potato @ {} called'.format(id(self))

spud = Potato()
fancy_spud = decorator(Potato())

通过这段代码,我们有两个可调用类的实例,一个是修饰的,一个是普通的:

>>> spud()
Potato @ 140408136280592 called
>>> fancy_spud()
With sour cream and chives! Potato @ 140408134310864 called

我想知道是否支持在仅一个实例的可调用对象上使用 @decorator 语法,而不是装饰类/方法,后者适用于每个实例。根据this流行的答案,@syntax 只是糖分:

function = decorator(function)

但这是否过于简单化了?在我所有半生不熟的尝试中,它似乎只在语法出现在 defclass、空格或 @another_decorator 之前时才有效。

@decorator
baked = Potato()

这是一个SyntaxError

baked = Potato()
@decorator
baked

还有语法错误

@decorator
def baked(_spud=Potato()):
    return _spud()

有效,但丑陋且有点作弊。

最佳答案

是的,这是过于简单化了。如果我们看the grammar , decorator 仅出现在规则 decorators 中,它仅作为 classdeffuncdef 的一部分出现:

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
decorated: decorators (classdef | funcdef)

什么 language reference says (我认为这是链接答案中重复的内容)是

@f1(arg)
@f2
def func(): pass

相当于

def func(): pass
func = f1(arg)(f2(func))

类定义也类似。但这并不意味着可以在任何地方应用 @decorator 语法;它仅在函数或类定义之前有效。

顺便说一句,即使是官方文档也不是严格正确的;在调用装饰器时,函数(或类)未绑定(bind)到封闭的命名空间或范围,因此给定的语法并不完全等同。

defclass 语句有一些有趣的地方,我认为这是它们是 @decorator< 唯一支持的语句的部分原因 语法:它们是 Python 中将名称绑定(bind)到知道该名称是什么的对象的唯一方法。

最后,这是调用您可能喜欢的装饰器的另一种方法:

@decorator
class baked:
    __metaclass__ = lambda *_: Potato()

关于python - 如何装饰可调用类的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24122444/

相关文章:

python - Gnuradio(3.7.9) : how to add a qt widget such as slider to the flowgraph?(新版本不支持pyqwt)

Python 如何编辑/更新 GitHub 要点?

python - 识别等效的可变参数函数调用以进行内存

python - 使用 nopython 模式在 numba 装饰器@njit 中为字符串的 ndarray 签名

python - Python中,用相同的名称修饰两个方法以区分它们

python - 用 flask 记录错误

python - 从字符串集合中查找最大长度

python - 最短路线优化不起作用

c++ - 使用 boost 和 python 绑定(bind)在 osx 上构建 32 位版本的 libtorrent

c# - 装饰 ASP.NET Web API IHttpController