Bill Prin
Bill Prin

Reputation: 2518

Attaching class as method

I discovered a slightly strange corner of Python I was hoping to get some help understanding.

Suppose I have a class B that I want to attach as a method for class A. I can do:

class A:
  def __init__(self):
    print("a self is %s " % self)

class B:
  def __init__(self):
    print("b self is %s " % self)

setattr(A, "B", B)

a = A()
a.B()

When I call a.B(), in the B.__init__ I get a self object for a new B instance.

Now suppose I want to capture the actual value of the a instance in the B constructor. I figured out you can do it with a wrapper function:

class A:
  def __init__(self):
    print("a self is %s " % self)

class B:
  def __init__(self, a_instance):
    print("b self is %s a_instance is %s " % (self, a_instance))

def _(*args, **kwargs):
  return B(*args, **kwargs)
setattr(A, "B", _)

a = A()
a.B()

With the wrapper function, a_instance will be passed in with the actual instance reference of the a object.

This is helpful to know, my problem is I really don't understand what's going on. I was hoping someone could provide a clearer explanation of why, if I just setattr with the B class, I do not get the a instance, but if I setattr with a wrapper around the B class that just calls it, I then do get the a instance.

Upvotes: 5

Views: 205

Answers (1)

askaroni
askaroni

Reputation: 993

FunctionType implements __get__ so that, when a function is called on an instance of a class on which its defined (i.e. as a bound_method), the owning instance (A here) is passed to it as the first argument. type doesn't have that __get__, so its instances, like B in your example, don't receive the owning instance when called.

@staticmethod is nearly always a mistake in real code, but you could use it on your function to emulate the behavior of the class here for demonstration purposes.

Upvotes: 2

Related Questions