Search code examples
pythonpython-object

Why does setting a method in a python class does not pass self when called?


If I write this:

class A:
    def a(self):
        return 2
    def b(self):
        print(self.a())

e = A()

def xa(self):
    return 3 

e.a = xa
e.b()

will explode saying that:

TypeError: xa() missing 1 required positional argument: 'self'

why does this happen? (if xa has no arguments then it works, printing 3, but then I can't access self).

This is for testing purposes, not actual production code


Solution

  • e.a = xa doesn't make xa a bound instance method (which would implicitly pass self), it's just some random function stored as an instance attribute.

    If you want it to act like a bound method, you have two options:

    1. Attach it to the class, e.g. A.a = xa (but that modifies the class itself, including all instances). This doesn't bind it on its own, but it will invoke the descriptor protocol when e.a is looked up, which triggers implicit binding.
    2. Manually bind it to the instance with types.MethodType, by adding import types to the top of your file, and changing the assignment to:

      e.a = types.MethodType(xa, e)  # First argument is function to bind, second is instance to bind to