为什么在实例化后设置在对象上的方法没有自动传递self?

15 投票
8 回答
3865 浏览
提问于 2025-04-16 07:33
 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!

撰写回答