为什么自我被自动传递给实例化后在对象上设置的方法?

时间:2010-11-24 13:48:53

标签: python

 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 个答案:

答案 0 :(得分:13)

它不是以你正在做的方式传递的。

你必须这样做。

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)提出answer表明这一点正在行动中。这是件好事。

答案 1 :(得分:7)

(这可以作为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!

答案 2 :(得分:3)

在这种情况下,say_hi不是你班级的方法。它只是对函数的引用。这就是自参数不会自动传递的原因。

或者只是使用:

class Person():

    def say_hi(self):
       print 'hii'

me=Person() me.say_hi=say_hi me.say_hi()

答案 3 :(得分:1)

自动传递方法的self参数。您没有方法,而是一个作为对象属性的函数。如果你做Person.say_hi = say_hi,那么Person()。say_hi()将按预期工作。方法是一个函数,它是类的属性,而不是实例,而self只传递给方法。

类属性定义实例应该如何工作,而实例属性只是您访问的正常属性。这意味着从实例访问类属性时会修改它们(例如,将函数转换为方法),而实例属性保持不变。

>>> class A(object): pass
... 
>>> def f(self): print self
... 
>>> ob = A()
>>> A.f = f
>>> ob.g = f
>>> print ob.f
<bound method A.f of <__main__.A object at 0xb74204ec>>
>>> print ob.g
<function f at 0xb7412ae4>
>>> ob.f()
<__main__.A object at 0xb74204ec>
>>> ob.g('test')
test

由于A是一个类,fA().fA.f是不同的东西。由于ob是一个对象,fob.g是相同的。

答案 4 :(得分:1)

因为函数say_hi()没有在person类中定义,所以它不知道self是什么,当你调用它时它没有将self传递给方法。这就像调用静态方法一样。

你可以这样做

me=Person()
me.say_hi=say_hi
me.say_hi(me)

答案 5 :(得分:1)

不,self不会自动传递给对象,因为它尚未在类块中定义。相反,您已在错误的块中定义了一个函数say_hi。当你运行它时,在这个上下文中的'self'实际上是一个函数的第一个参数,它在类块之外,因此不是类的一部分,因此就是错误。

答案 6 :(得分:0)

我想你想这样做

say_hi(me)

但编程OO的常用方法是:

class Person:
   def say_hi(self):
      print 'hii'

me = Person()
me.say_hi()

答案 7 :(得分:0)

也许这有用吗?

class Person():
 def say_hi(self):
  print 'hii'
me=Person()
me.say_hi()

我把这个函数放在了类中,因为我觉得那就是你想要的。然后你可以稍后从类对象我调用它。