为什么在下面的代码中,使用类变量作为方法指针会导致未绑定方法错误,而使用普通变量可以正常工作:
class Cmd:
cmd = None
@staticmethod
def cmdOne():
print 'cmd one'
@staticmethod
def cmdTwo():
print 'cmd two'
def main():
cmd = Cmd.cmdOne
cmd() # works fine
Cmd.cmd = Cmd.cmdOne
Cmd.cmd() # unbound error !!
if __name__=="__main__":
main()
完全错误:
^{pr2}$
我喜欢从“自下而上”的角度看待这种行为。在
Python中的函数充当“descriptor object”。因此,它有一个
__get__()
方法。在对具有这样一个
__get__()
方法的类属性的读取访问被“重定向”到此方法。对类的属性访问被执行为attribute.__get__(None, containing_class)
,而对实例的属性访问被映射到attribute.__get__(instance, containing_class)
。在函数的
__get__()
方法的任务是将函数包装在一个方法对象中,该对象包装了self
参数-对于实例的属性访问。这称为绑定方法。在在2.x上的类属性访问中,函数的
__get__()
返回一个未绑定的方法包装器,而在3.x上,函数的learned today返回自身。(请注意,__get__()
机制仍然存在于3.x中,但是函数只返回自身。)这几乎是相同的,如果你看看它是如何调用的,但是一个未绑定的方法包装器会额外检查self
参数的正确类型。在staticmethod()
调用只创建一个对象,该对象的__get__()
调用旨在返回最初给定的对象,从而撤消所描述的行为。这就是HYRY's trick的工作原理:属性acces撤消staticmethod()
包装,调用再次执行此操作,以便“new”属性与旧属性具有相同的状态,尽管在本例中,staticmethod()
似乎应用了两次(但实际上不是)。在(顺便说一句:它甚至在这种奇怪的背景下也能起作用:
尽管
8
不是函数,2
不是类。)在你的问题中,你有两种情况:
^{pr2}$访问该类并请求其
^{3}$cmdOne
属性,staticmethod()
对象。它通过其__get__()
进行查询,并返回原始函数,然后调用该函数。这就是为什么它工作得很好。在执行相同的操作,但将此函数分配给
Cmd.cmd
。下一行是属性访问-它再次对函数本身进行__get__()
调用,因此返回一个未绑定的方法,该方法必须以正确的self
对象作为第一个参数来调用。在您需要使用
staticmethod()
来转换函数:在Python2.x中,您遇到了“unbound methods”的行为。基本上,在Python2.x中,当您获得一个类的属性(例如,在本例中是{}),并且值是一个函数时,类将函数“包装”到一个特殊的“unbound method”对象中,因为它们假定类的属性是函数而不是函数用
staticmethod
或classmethod
修饰的是实例方法(在本例中是一个错误的假设)。此未绑定方法在调用时需要一个参数,即使在本例中基础函数不需要参数。在此行为在language reference中解释:
(在“类”部分)
(在“用户定义方法”部分)
[…]
这就是导致你看到的错误的原因。在
您可以显式地从method对象中检索底层函数并调用它(但显然需要这样做并不理想):
注意python3.xgot rid of unbound methods和您的代码在python3.x上运行良好
相关问题 更多 >
编程相关推荐