Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python function pointer in class __init__

In the code below, class A has a member function which is set to point to a function defined outside the class. in class B, the same function is set to the external pointer in the class definition. Calling the function for an object of type A will fail, because the self does not get passed to the function. But for B, the self gets passed. Why does the self get passed for B, but not for A?

def f1(s,a):
    print s
    print a

class A(object):
    def __init__(self):
        self.fp1 = f1

class B(object):
    fp1 = f1

a=A()
b=B()
try:a.fp1("blaa")
except Exception, e: print `e` 
try:b.fp1("bluu")
except Exception, e: print `e` 

Output:

TypeError('f1() takes exactly 2 arguments (1 given)',)
<__main__.B object at 0x2ab0dacabed0>
bluu
like image 503
Nutiu Lucian Avatar asked Mar 27 '26 16:03

Nutiu Lucian


2 Answers

When you did self.fp1 = f1 you just assigned a function to an instance variable of the class A. So when you call it you have to pass two arguments.

When you did:

   class B(object):
       fp1 = f1

during creation process of the class B python found a function fp1 in the class scope and created an instancemethod from it (replaced the variable with name fp1 with an instancemethod created from the function that it held before). When you call an instancemethod on an object self gets automatically passed as the first argument.

You can check this by typing:

>>> a = A()
>>> b = B()
>>> type(a.fp1)
function
>>> type(b.fp1)
instancemethod
like image 57
Viktor Kerkez Avatar answered Mar 31 '26 09:03

Viktor Kerkez


In class A you bind a function to an instance. This could be really considered as "function pointer" so all arguments must be passed explicitly. In class B you bind the function to the class which will cause the function to work as method. You could modify class definition A to

class A(object):
    def __init__(self):
        A.fp1 = f1

which will give the same behavior has class B, i.e. fp1 of all instances points to f1, or you could wrap f1.

class A(object):
    def __init__(self):
        self.fp1 = lambda a: f1(self, a)

This will allow to change fp1 for each instance individually. The latter variant is probably what you were looking for.

like image 35
dastrobu Avatar answered Mar 31 '26 11:03

dastrobu