Reputation: 2518
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
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