Bas*_*ani 5 python static-methods function-pointers
为什么在下面的代码中,使用类变量作为方法指针会导致未绑定的方法错误,而使用普通变量可以正常工作:
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()
Run Code Online (Sandbox Code Playgroud)
完整的错误:
TypeError: unbound method cmdOne() must be called with Cmd instance as
first argument (got nothing instead)
Run Code Online (Sandbox Code Playgroud)
我喜欢从“自下而上”的角度看待这种行为。
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
Run Code Online (Sandbox Code Playgroud)
虽然8不是函数2也不是类。)
你的问题有两种情况:
cmd = Cmd.cmdOne
cmd() # works fine
Run Code Online (Sandbox Code Playgroud)
访问该类并请求其cmdOne属性(一个staticmethod()对象)。这是通过 it 查询__get__()并返回原始函数,然后调用该函数。这就是为什么它工作得很好。
Cmd.cmd = Cmd.cmdOne
Cmd.cmd() # unbound error
Run Code Online (Sandbox Code Playgroud)
执行相同的操作,但随后将此函数分配给Cmd.cmd. 下一行是属性访问 - 它再次调用__get__()函数本身,从而返回一个未绑定的方法,必须使用正确的self对象作为第一个参数来调用该方法。