Why isn't self being automatically passed to a method that is set on an object after its instantiation?
class Person():
pass;
def say_hi(self):
print 'hii'
me=Person()
me.say_hi=say_hi
me.say_hi()
Isn't the self argument automatically passed in python ? why why is calling me.say_hi()
is giving a stack trace ?
Traceback (most recent call last):
File "<input>", lin开发者_如何学Pythone 1, in <module>
TypeError: say_hi() takes exactly 1 argument (0 given)
It's not passed in the way that you are doing it.
You would have to do.
import types
me.say_hi = types.MethodType(say_hi, me, Person)
for it to work.
When python instantiates a class, it essentially carries out the above procedure for each of the class methods. When you 'monkey-patch' a method onto an object in the way that you were trying to do it, it's not a bound method and just exists as a function in instance.__dict__
. Calling it is no different than calling any other function. If you want to stick a method on an instance, you have to manually make it a method as shown above.
If you were to do
class Person(object):
pass
def say_hi(self):
print 'hii'
Person.say_hi = say_hi
me = Person()
me.say_hi()
then it would work because Python will create the method for you.
Chris Morgan put up an answer that shows this one in action. It's good stuff.
(This can act as some demonstration for aaronasterling's answer.)
Here are the definitions:
>>> class Person(object):
... def bound(self):
... print "Hi, I'm bound."
...
>>> def unbound(self):
... print "Hi, I'm unbound."
...
Note the types of these methods and functions.
>>> type(Person.bound)
<type 'instancemethod'>
>>> type(Person().bound)
<type 'instancemethod'>
>>> type(unbound)
<type 'function'>
>>> Person.unbound = unbound
When it gets set on the Person
before instantiation, it gets bound.
>>> Person().bound()
Hi, I'm bound.
>>> Person().unbound()
Hi, I'm unbound.
However, if it's set after instantiation, it's still of type '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)
The 'instancemethod' type can be used to bind a 'function' to an object. It's in the types
module as MethodType
.
>>> import types
>>> me.rebound = types.MethodType(unbound, me, Person)
Now it's bound properly.
>>> type(me.rebound)
<type 'instancemethod'>
>>> me.rebound()
Hi, I'm unbound.
>>> # Not true any more!
In this case say_hi is not method of your class. It is just reference to a function. This is why the self argument is not passed automatically.
Or just use:
class Person():
def say_hi(self):
print 'hii'
me=Person() me.say_hi=say_hi me.say_hi()
The self argument of a method is passed automatically. You don't have a method, but a function that is an attribute of an object. If you did Person.say_hi = say_hi
, then Person().say_hi() would work as expected. A method is a function that's attribute of a class, not an instance, and self is passed only for methods.
Class attributes define how the instances should work, while instance attributes are just normal you access. This means that class attributes are modified when they are accessed from an instance (e.g. functions are turned into methods), while instance attributes are left unchanged.
>>> 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
Since A
is a class, f
, A().f
and A.f
are different things. Since ob
is an object, f
and ob.g
are the same thing.
because the function say_hi()
wasn't defined inside of the person class it doesn't know what self
is, and when you call it it isn't passing self
to the method. This would be like calling a static method.
you could do this though
me=Person()
me.say_hi=say_hi
me.say_hi(me)
No, self is not automatically passed to the object, because it has not been defined within the class block. Instead, you have defined a function, say_hi, in the wrong block. When you run it, 'self' in this context, is actually the first parameter of a function which is outside the class block, and therefore not a part of the class, hence the error.
i think you wanted to do this
say_hi(me)
but the usual way to program OO is this:
class Person:
def say_hi(self):
print 'hii'
me = Person()
me.say_hi()
maybe this works?
class Person():
def say_hi(self):
print 'hii'
me=Person()
me.say_hi()
I put the function inside the class because I feel thats what you wanted. Then you can call it later from the class object me.
精彩评论