python - 装饰类的方法会导致 2.7 中的未绑定方法 TypeError
问题描述
每当我在类定义之外装饰类的方法并使用它时,它都会抛出一个 TypeError 说 unbound method with class instance as first argument 。
我正在使用 setattr() 方法设置装饰方法。例如:
class A(object):
@classmethod
def demo_method(cls, a):
print a
def decorator(function):
from functools import wraps
@wraps(function)
def wrapper(*args, **kwargs):
return_value = function(*args, **kwargs)
return return_value
return wrapper
setattr(A, 'demo_method', decorator(A.demo_method))
A.demo_method(1)
它抛出以下错误:
TypeErrorTraceback (most recent call last)
<ipython-input-13-447ee51677f4> in <module>()
17 setattr(A, 'demo_method', decorator(A.demo_method))
18
---> 19 A.demo_method(1)
20
TypeError: unbound method demo_method() must be called with A instance as first argument (got int instance instead)
解决方案
您看到的行为实际上与装饰器本身的使用无关。你也可以这样说:
class C(object):
pass
setattr(C, 'm', lambda a: a) # actually also just: C.m = lambda a: a
print(C.m(1))
你仍然会得到基本相同的错误。您可以在 Python 2 文档中阅读更多关于User-defined methods 的内容,即这些位:
请注意,每次从类或实例中检索属性时,都会发生从函数对象到(未绑定或绑定)方法对象的转换。...还要注意,这种转换只发生在用户定义的函数上;其他可调用对象(和所有不可调用对象)无需转换即可检索。同样重要的是要注意,作为类实例属性的用户定义函数不会转换为绑定方法;这只发生在函数是类的属性时。
你遇到的例外是因为:
当调用未绑定的用户定义方法对象时,将调用底层函数 (im_func),但第一个参数必须是正确类 (im_class) 或其派生类的实例。
如果您仔细查看C.m
,您会看到:
>>> print(C.m)
<unbound method C.<lambda>>
>>> print(C().m)
<bound method C.<lambda> of <__main__.C object at 0x7f6f6c5fa850>>
而对于 Python 3(正如评论中暗示的那样,这个结构会通过),行为将是:
>>> print(C.m)
<function <lambda> at 0x7f69fbe8d0d0>
>>> print(C().m)
<bound method <lambda> of <__main__.C object at 0x7f69fbe89940>>
请注意C.m
,在后一种情况下,仍然作为(普通)函数而不是(未绑定)方法访问。
我不完全确定您最终的目标是什么以及最有用的方向是什么,但是为了获得与此代码在 Python 3 中相同的行为,您可以更改(不是我建议它)C.m()
调用C.m.__func__()
一个来直接访问底层函数。或者用你的例子:
A.demo_method.__func__(1)
推荐阅读
- c++ - 带有 CMake 的 QtCreator,在编辑器中错误地解析了 __cplusplus 值
- jquery - 超过其最大高度后如何为div应用滚动条
- javascript - 如何优化我的代码以确保它锁定每个单元格?
- elasticsearch - 为 Elastic Search 中的对象数组编写查询
- go - Go:在套件运行后打印文本?
- python - 为什么对象的地址在 Python 中有奇怪的行为?
- python - 在 Keras“ImageDataGenerator”中,“validation_split”参数是一种 K 折交叉验证吗?
- javascript - 如何在firebase函数中处理一个有点大的CSV文件
- c# - 如何使 HttpClient 在 sonarqbue 中安全发送
- javascript - 无法读取从烧瓶发送到 javascript 的对象 BoundingPoly。想在 html 中使用这个边界并在图像上绘制这个边界