指针在Python静态方法(Pointers to static methods in Python

2019-09-01 04:32发布

为什么在下面的代码,使用类变量作为不受约束的方法错误的方法指针的结果,而使用普通的变量正常工作:

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)

Answer 1:

我喜欢从“自下而上”查看此行为。

Python中的功能作为“ 描述符对象 ”。 因此,它具有__get__()方法。

到具有这样的一类属性的读访问__get__()方法“重定向”于该方法。 到A类属性访问作为执行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对象作为第一个参数。



Answer 2:

您需要使用staticmethod()的函数转换:

Cmd.cmd = staticmethod(Cmd.cmdOne)


Answer 3:

您正在运行到的“未绑定方法”在Python 2.x的行为 基本上,在Python 2.x中,当你的类的属性(在这种情况下例如Cmd.cmd ),并且该值是一个函数,那么类“换行”的功能进入一个特殊的“未结合的方法”的对象,因为他们认为那是功能,而不是装饰的类属性的staticmethodclassmethod的意思是实例方法(在这种情况下,不正确的假设)。 这种不受约束的方法期待的参数调用时,即使在这种情况下,底层函数的不期望的说法。

这种行为在解释语言参考 :

(在“类”部分)

当一个类属性引用(C类,比方说)将产生一个用户定义的功能对象或[...],它被变换成其im_class属性是C.未绑定用户定义的方法对象

(在“用户定义的方法”部分)

当通过从一类检索用户定义的函数对象创建一个用户定义的方法对象,其属性im_self是无并且该方法对象被说成是未结合的。

[...]

当未结合的用户定义的方法对象被调用时,底层函数(im_func)被调用时,与该第一个参数必须是正确的类(im_class)的一个实例的限制或其派生类的。

这是什么原因造成的,你看到的错误。

你可以明确地检索底层函数该方法对象并调用(但它显然不是理想的需要这样做):

Cmd.cmd.im_func()

需要注意的是Python 3.x都有摆脱结合的方法 ,你的代码将运行在Python 3.x都有微细



文章来源: Pointers to static methods in Python