我遇到了方法覆盖的问题。
查看下面的src代码,
class Foo(object):
@staticmethod
def bar():
pass
Foo.bar() # works fine
print Foo.bar # <function bar at 0x028A5B30>
print dir(Foo.bar)
"""
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',
'__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__',
'__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict',
'func_doc', 'func_globals', 'func_name']
"""
backup = Foo.bar # keep the instance of the method object
Foo.bar = backup # overwrite with the same method object
print Foo.bar # <unbound method Foo.bar>
print dir(Foo.bar)
"""
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__format__',
'__func__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__', 'im_class', 'im_func', 'im_self']
"""
Foo.bar() # TypeError: unbound method foo() must be called with Test instance as first argument (got nothing instead)
有趣的是,Foo.bar.im_func属性实际上是方法,并且在调用时工作得很好。我想知道是否有办法用im_func属性恢复Foo.bar方法?请指教〜
谢谢!
答案 0 :(得分:6)
如果您希望它继续是静态方法,那么在分配时必须告诉Python。否则它将成为一种正常的方法。
Foo.bar = staticmethod(backup)
答案 1 :(得分:3)
如果将一个函数作为一个属性放到一个对象上,事情会变得混乱:由于它们的__get__()
方法,它们的行为与它们出现的不同。为了正确理解,您应该阅读Python文档中的the section about data descriptors。
一个函数是一个__get__()
方法,它将使该函数显示为方法。
假设你有
def f(a): pass
class C(object):
def m(a): pass # method
sm = staticmethod(m)
cm = classmethod(m)
o = C()
f
然后是<function f at 0xb742c87c>
,C.__dict__['m']
也一样。f.__get__(None, object)
返回方法对象<unbound method object.f>
。如果被调用,它会检查是否使用给定类的实例调用它,在本例中为object
。如果属性访问包含函数作为方法的类,或使用C.m
,则相当于C.__dict__['m'].__get__(None, C)
并生成<unbound method C.m>
。f.__get__(4, object)
生成<bound method object.f of 4>
。它将调用绑定到对象4
的原始函数,并在每次调用时将其作为第一个参数传递。这种情况发生在对类实例的属性访问中。因此,o.m
会调用C.__dict__['m'].__get__(o, C)
并产生<bound method C.m of <__main__.C object at 0x...>>
。简而言之:
>>> C.__dict__['m']
<function m at 0xb73bcd84>
>>> C.m
<unbound method C.m>
>>> C.m.im_class, C.m.im_self
(<class '__main__.C'>, None)
>>> C.__dict__['m'].__get__(None, C)
<unbound method C.m>
>>> o.m
<bound method C.m of <__main__.C object at 0xb73c64ac>>
>>> o.m.im_class, o.m.im_self
(<class '__main__.C'>, <__main__.C object at 0xb73c64ac>)
>>> C.__dict__['m'].__get__(o, C)
<bound method C.m of <__main__.C object at 0xb73c64ac>>
如果将staticmethod()
应用于某个函数,然后将其分配给该类中的属性,则会得到类似的行为:staticmethod
对象是__get__()
不生成的对象方法对象但原始函数本身。参见
>>> C.__dict__['sm']
<staticmethod object at 0xb73cd62c>
>>> C.sm
<function m at 0xb73bcd84>
>>> C.__dict__['sm'].__get__(None, C)
<function m at 0xb73bcd84>
>>> o.sm
<function m at 0xb73bcd84>
>>> C.__dict__['sm'].__get__(o, C)
<function m at 0xb73bcd84>
要完成,classmethod()
的工作原理如下:
>>> C.__dict__['cm']
<classmethod object at 0xb73cd794>
>>> C.cm
<bound method type.m of <class '__main__.C'>>
>>> C.cm.im_class, C.cm.im_self
(<type 'type'>, <class '__main__.C'>)
>>> o.cm
<bound method type.m of <class '__main__.C'>>
>>> o.cm.im_class, o.cm.im_self
(<type 'type'>, <class '__main__.C'>)
>>> C.__dict__['cm'].__get__(type(C), C)
<bound method type.m of <class '__main__.C'>>
那就是说,你可以看到你的情况会发生什么:首先,你有一个静态的方法。但是
backup = Foo.bar
您获得原始功能,但未应用staticmethod
。在回来的路上,
Foo.bar = backup
,将函数赋值给属性,使其成为具有上述含义的类的普通方法,需要使用Foo
实例调用(即使函数本身不接受任何参数,这不是方法对象的业务)并自动调用它,其他参数前置于其他参数。