覆盖的方法不包含自我?

时间:2013-06-18 08:27:47

标签: python python-2.7

以下是我刚在机器上播放的示例:

$ python
Python 2.7.4 (default, Apr 19 2013, 18:28:01) 
[GCC 4.7.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
# just a test class 
>>> class A(object):
...   def hi(self):
...     print("hi")
... 
>>> a = A()
>>> a.hi()
hi
>>> def hello(self):
...   print("hello")
... 
>>> 
>>> hello(None)
hello
>>> 
>>> 
>>> 
>>> a.hi = hello
# now I would expect for hi to work the same way as before
# and it just prints hello instead of hi.
>>> a.hi()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: hello() takes exactly 1 argument (0 given)
>>> 
>>> def hello():
...   print("hello")
... 
# but instead this one works, which doesn't contain any
# reference to self
>>> a.hi = hello
>>> a.hi()
hello
>>> 
>>> 
>>> 
>>> 
>>> a.hello = hello
>>> a.hello()
hello

这里发生了什么?当函数用作方法时,为什么函数不能获取参数self?我需要做什么,才能在里面引用自我?

2 个答案:

答案 0 :(得分:8)

通过实例引用的类中的方法绑定到该实例,在您的情况下:

In [3]: a.hi
Out[3]: <bound method A.hi of <__main__.A object at 0x218ab10>>

比较:

In [4]: A.hi
Out[4]: <unbound method A.hi>

所以,为了达到你想要的效果,做

In [5]: def hello(self):
   ...:     print "hello"
   ...:     

In [6]: A.hi = hello

In [7]: a.hi()
hello

注意 - 这将适用于A的所有实例。但是如果你只想在一个实例上覆盖一个方法,你真的需要传递self吗?

答案 1 :(得分:3)

当它们是类属性时,它是访问函数的方式。

作为类属性添加的函数将作为descriptor进行访问。如果你这样做,你会看到

class A(object):
    pass

def f(*a): pass
A.f = f
print f
print A.f
print A().f

在这里,你得到了输出

<function f at 0x00F03D70>
<unbound method A.f>
<bound method A.f of <__main__.A object at 0x00F089D0>>

你得到的相同输出

print f
print f.__get__(None, A)
print f.__get__(A(), A)

因为这就是描述符的工作方式。

所有这些 - 通过描述符协议从函数到方法的转换 - 不会发生在实例属性上。

如果你这样做

a = A()
a.f = f

然后a.f也作为函数读回,而不是作为方法。因此,您应该在执行任务时考虑这一点,而不是

a.f = lambda: f(a)

以便将a传递给函数。