gpt4 book ai didi

python - 装饰一个已经是类方法的方法?

转载 作者:太空狗 更新时间:2023-10-29 22:27:38 25 4
gpt4 key购买 nike

今天早上我遇到了一个有趣的问题。我有一个看起来像这样的基类:

# base.py
class Base(object):

@classmethod
def exists(cls, **kwargs):
# do some work
pass

还有一个看起来像这样的装饰器模块:

# caching.py

# actual caching decorator
def cached(ttl):
# complicated

def cached_model(ttl=300):
def closure(model_class):
# ...
# eventually:
exists_decorator = cached(ttl=ttl)
model_class.exists = exists_decorator(model_class.exists))

return model_class
return closure

这是我的子类模型:

@cached_model(ttl=300)
class Model(Base):
pass

问题是,当我实际调用 Model.exists 时,我收到关于参数数量错误的投诉!检查装饰器中的参数没有发现任何奇怪的事情 - 参数正是我所期望的,并且它们与方法签名匹配。如何向已使用 classmethod 装饰的方法添加更多装饰器?

并非所有模型都被缓存,但是 exists() 方法作为类方法存在于每个模型中,因此重新排序装饰器不是一个选项:cached_model 可以将类方法添加到 exists( ),那么是什么让 exists() 成为未缓存模型上的类方法呢?

最佳答案

在 Python 中,当一个方法被声明时,在一个函数体中,它就像一个函数——一旦类被解析并存在,通过“.”检索方法。运算符将该函数 - 即时 - 转换为方法。此转换确实将第一个参数添加到方法中(如果它不是静态方法)-

所以:

>>> class A(object):
... def b(self):
... pass
...
>>> A.b is A.b
False

因为每次检索“A”的“b”属性都会产生“方法对象 b”的不同实例

>>> A.b
<unbound method A.b>

原始函数“b”可以在不进行任何转换的情况下检索

>>> A.__dict__["b"]
<function b at 0xe36230>

对于用 @classmethod 修饰的函数,同样的情况会发生,当从 A 中检索值“class”时,它会被添加到参数列表中。

@classmethod@staticmethod 装饰器会将底层函数包装在与普通实例方法不同的描述符中。一个类方法对象——当它被 classmethod 包装时,函数变成了一个描述符对象,它有一个“__get__”方法,该方法将返回一个包装底层函数的函数——并添加“cls "参数在所有其他参数之前。

@classmethod 的任何进一步装饰器都必须“知道”它实际上是在处理描述符对象,而不是函数。 -

>>> class A(object):
... @classmethod
... def b(cls):
... print b
...
>>> A.__dict__["b"]
<classmethod object at 0xd97a28>

因此,让 @classmethod 装饰器成为最后一个应用于该方法的装饰器(堆栈中的第一个装饰器)要容易得多 - 这样其他装饰器就可以继续工作一个简单的函数(知道“cls”参数将作为第一个插入)。

关于python - 装饰一个已经是类方法的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8977359/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com