指向Python中的静态方法

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)

glg*_*lgl 2

我喜欢从“自下而上”的角度看待这种行为。

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对象作为第一个参数来调用该方法。