为什么在下面的代码中,使用类变量作为方法指针会导致未绑定的方法错误,而使用普通变量则可以正常工作:
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()
完整错误:
TypeError: unbound method cmdOne() must be called with Cmd instance as first argument (got nothing instead)
我喜欢从下至上查看这种行为。
Python中的函数充当“描述符对象”。因此,它具有一种__get__()方法。
__get__()
对具有此类__get__()方法的类属性的读取访问将“重定向”到该方法。对类的属性访问以方式执行attribute.__get__(None, containing_class),而对实例的属性访问则映射到attribute.__get__(instance, containing_class)。
attribute.__get__(None, containing_class)
attribute.__get__(instance, containing_class)
函数的__get__()方法的任务是将函数包装在一个方法对象中,该对象将包装self参数-对于对实例的属性访问而言。这称为绑定方法。
self
在2.x上进行类属性访问时,函数__get__()将返回一个未绑定的方法包装器,而正如我今天所了解的那样,在3.x上它将返回自身。(请注意,该__get__()机制在3.x中仍然存在,但是函数只是返回自身。)如果您看一下如何调用它,则几乎是相同的,但是未绑定的方法包装器还会检查self参数的正确类型。
一个staticmethod()呼叫只是创建一个对象,它__get__()调用用于返回最初给出的对象,使其撤销所描述的行为。这就是HYRY的诀窍的工作方式:属性acces取消staticmethod()包装,调用再次进行该操作,以便“新”属性与旧属性具有相同的状态,尽管在这种情况下,staticmethod()似乎应用了两次(但实际上不是) )。
staticmethod()
(顺便说一句:它甚至可以在这种怪异的情况下工作:
s = staticmethod(8) t = s.__get__(None, 2) # gives 8
虽然8不是函数,2也不是类。)
8
2
在您的问题中,您有两种情况:
cmd = Cmd.cmdOne cmd() # works fine
访问该类并询问其cmdOne属性,即staticmethod()对象。通过其查询__get__()并返回原始函数,然后调用原始函数。这就是为什么它可以正常工作的原因。
cmdOne
Cmd.cmd = Cmd.cmdOne Cmd.cmd() # unbound error
执行相同的操作,但是将此功能分配给Cmd.cmd。下一行是属性访问- 再次__get__()执行对函数本身的调用,因此返回未绑定的方法,必须以正确的self对象作为第一个参数来调用该方法。
Cmd.cmd