为什么在实例化后设置在对象上的方法没有自动传递self?
class Person():
pass;
def say_hi(self):
print 'hii'
me=Person()
me.say_hi=say_hi
me.say_hi()
在Python中,self这个参数不是自动传递的吗?为什么调用me.say_hi()
会出现堆栈跟踪错误呢?
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: say_hi() takes exactly 1 argument (0 given)
8 个回答
3
在这种情况下,say_hi 不是你类里的一个方法。它只是一个函数的引用。这就是为什么 self 参数不会自动传递的原因。
或者你可以直接使用:
class Person():
def say_hi(self):
print 'hii'
me=Person() me.say_hi=say_hi me.say_hi()
14
你这样做并不能传递。
你需要这样做。
import types
me.say_hi = types.MethodType(say_hi, me, Person)
这样才能正常工作。
当Python创建一个类的时候,它实际上会对每个类的方法执行上面的过程。当你试图像这样给一个对象添加一个方法时,这个方法并不是一个绑定的方法,而只是存在于instance.__dict__
中的一个函数。调用它和调用其他任何函数没有区别。如果你想把一个方法加到一个实例上,你必须手动将它变成一个方法,就像上面那样。
如果你这样做:
class Person(object):
pass
def say_hi(self):
print 'hii'
Person.say_hi = say_hi
me = Person()
me.say_hi()
那么它就能工作,因为Python会为你创建这个方法。
Chris Morgan 提供了一个 答案,展示了这个方法的实际效果。内容很不错。
12
(这可以作为对aaronasterling回答的一个示范。)
下面是一些定义:
>>> class Person(object):
... def bound(self):
... print "Hi, I'm bound."
...
>>> def unbound(self):
... print "Hi, I'm unbound."
...
注意这些方法和函数的类型。
>>> type(Person.bound)
<type 'instancemethod'>
>>> type(Person().bound)
<type 'instancemethod'>
>>> type(unbound)
<type 'function'>
>>> Person.unbound = unbound
当它在创建Person
对象之前被设置时,它就被绑定了。
>>> Person().bound()
Hi, I'm bound.
>>> Person().unbound()
Hi, I'm unbound.
但是,如果是在创建对象之后设置的,它仍然是'function'类型。
>>> me = Person()
>>> me.rebound = unbound
>>> type(me.rebound)
<type 'function'>
>>> type(me.unbound)
<type 'instancemethod'>
>>> me.rebound
<function unbound at 0x7fa05efac9b0>
>>> me.rebound()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound() takes exactly 1 argument (0 given)
'instancemethod'类型可以用来将一个'function'绑定到一个对象上。它在types
模块中被称为MethodType
。
>>> import types
>>> me.rebound = types.MethodType(unbound, me, Person)
现在它已经正确绑定了。
>>> type(me.rebound)
<type 'instancemethod'>
>>> me.rebound()
Hi, I'm unbound.
>>> # Not true any more!