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