指向Python中静态方法的指针

2024-04-26 18:45:50 发布

您现在位置: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()

完全错误:

^{pr2}$

Tags: 方法代码cmdnonemaindef错误one
3条回答

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

Python中的函数充当“descriptor object”。因此,它有一个__get__()方法。在

对具有这样一个__get__()方法的类属性的读取访问被“重定向”到此方法。对类的属性访问被执行为attribute.__get__(None, containing_class),而对实例的属性访问被映射到attribute.__get__(instance, containing_class)。在

函数的__get__()方法的任务是将函数包装在一个方法对象中,该对象包装了self参数-对于实例的属性访问。这称为绑定方法。在

在2.x上的类属性访问中,函数的__get__()返回一个未绑定的方法包装器,而在3.x上,函数的learned today返回自身。(请注意,__get__()机制仍然存在于3.x中,但是函数只返回自身。)这几乎是相同的,如果你看看它是如何调用的,但是一个未绑定的方法包装器会额外检查self参数的正确类型。在

staticmethod()调用只创建一个对象,该对象的__get__()调用旨在返回最初给定的对象,从而撤消所描述的行为。这就是HYRY's trick的工作原理:属性acces撤消staticmethod()包装,调用再次执行此操作,以便“new”属性与旧属性具有相同的状态,尽管在本例中,staticmethod()似乎应用了两次(但实际上不是)。在

(顺便说一句:它甚至在这种奇怪的背景下也能起作用:

s = staticmethod(8)
t = s.__get__(None, 2) # gives 8

尽管8不是函数,2不是类。)

在你的问题中,你有两种情况:

^{pr2}$

访问该类并请求其cmdOne属性,staticmethod()对象。它通过其__get__()进行查询,并返回原始函数,然后调用该函数。这就是为什么它工作得很好。在

^{3}$

执行相同的操作,但将此函数分配给Cmd.cmd。下一行是属性访问-它再次对函数本身进行__get__()调用,因此返回一个未绑定的方法,该方法必须以正确的self对象作为第一个参数来调用。在

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

Cmd.cmd = staticmethod(Cmd.cmdOne)

在Python2.x中,您遇到了“unbound methods”的行为。基本上,在Python2.x中,当您获得一个类的属性(例如,在本例中是{}),并且值是一个函数时,类将函数“包装”到一个特殊的“unbound method”对象中,因为它们假定类的属性是函数而不是函数用staticmethodclassmethod修饰的是实例方法(在本例中是一个错误的假设)。此未绑定方法在调用时需要一个参数,即使在本例中基础函数不需要参数。在

此行为在language reference中解释:

(在“类”部分)

When a class attribute reference (for class C, say) would yield a user-defined function object or [...], it is transformed into an unbound user-defined method object whose im_class attribute is C.

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

When a user-defined method object is created by retrieving a user-defined function object from a class, its im_self attribute is None and the method object is said to be unbound.

[…]

When an unbound user-defined method object is called, the underlying function (im_func) is called, with the restriction that the first argument must be an instance of the proper class (im_class) or of a derived class thereof.

这就是导致你看到的错误的原因。在

您可以显式地从method对象中检索底层函数并调用它(但显然需要这样做并不理想):

Cmd.cmd.im_func()

注意python3.xgot rid of unbound methods和您的代码在python3.x上运行良好

相关问题 更多 >