2

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

gotch4
  • 13,093
  • 29
  • 107
  • 170
  • 1
    `self` is just a name. You can write `mickeyMouse` instead of `self` and everything works the same. If you want to define an instance method instead of an instance attribute that happens to be a callable you want to set the attribute on the class. – Giacomo Alzetta Aug 29 '19 at 15:42
  • Good explanation [here](https://stackoverflow.com/a/114267/1916917) – Holloway Aug 29 '19 at 15:45

1 Answers1

7

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
    
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271