Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't self being automatically passed to a method that is set on an object after its instantiation?

Tags:

python

 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>", line 1, in <module>
TypeError: say_hi() takes exactly 1 argument (0 given)
like image 214
Bunny Rabbit Avatar asked Nov 24 '10 13:11

Bunny Rabbit


People also ask

Is self automatically passed in Python?

Use self when: you define an instance method, since it is passed automatically as the first parameter when the method is called; you reference a class or an instance attribute from inside an instance method; you want to refer to instance variables and methods from other instance methods.

What is self and why does it appear in methods that we define in a class?

self represents the instance of the class. By using the “self” we can access the attributes and methods of the class in python. It binds the attributes with the given arguments. The reason you need to use self. is because Python does not use the @ syntax to refer to instance attributes.

Why is self not defined Python?

The “NameError: name 'self' is not defined” error is raised when you forget to specify “self” as a positional argument or when you use “self” in another argument in a list of arguments. You solve this error by making sure that all methods in a function that use “self” include “self” in their list of arguments.

What is the purpose of the self parameter in a method?

The self parameter is a reference to the current instance of the class, and is used to access variables that belongs to the class.


2 Answers

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.

like image 78
aaronasterling Avatar answered Sep 17 '22 12:09

aaronasterling


(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!
like image 34
Chris Morgan Avatar answered Sep 17 '22 12:09

Chris Morgan