2

I am working in a dynamic programming environment where I might need to define (or redefine) a class function. So consider this for example:

def func(self):
    print("hello2 \n")

class ManClass:
    def __init__(self):
        pass
    def func1(self):
        print("hello1\n")

a = ManClass()

a.func1()
hello1

a.func2 = func
>>> a.func2()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() takes exactly 1 argument (0 given)

If func2() had been defined inside the class - a.func2() would have been interpreted as ManClass.func2(a) - but now that I am assigning it outside, it seems to expect an argument. How do I fix this, but more importantly, why this difference in how the two definitions are interpereted ?

2 Answers2

2

You didn't add func to the class, you added it to an instance. Try ManClass.func2 = func instead.

a.func2 = func adds func to the a instance of the class as an instance attribute named func2, not as an instance member method (which is really just special handling for callable members on the underlying class object).

Alternatively, you can also add a member method to a single instance using MethodType, as @jonrsharpe points out in his answer.

Silas Ray
  • 25,682
  • 5
  • 48
  • 63
  • Oh snap, you're right. Class and instance attributes/functions are 'different'. I should've known what I was doing wrong. Thanks a lot ! – user1922297 Jan 15 '14 at 23:44
2

This is the difference between a function and a bound method, where "bound" refers to the instance self. To fix your problem, you need to make the standalone function MethodType:

from types import MethodType

a.func2 = MethodType(func, a)

This binds the func to the ManClass instance a, allowing it to access any instance attributes. Note that this only affects a, other ManClass instances will retain the original class definition unless similarly patched.

When you simply attach the function

a.func2 = func

you can still access it:

a.func2(None) # will print "hello2 \n"

But it doesn't get the implicit object instance self parameter and just treats it as a standard positional argument.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437