How can I "steal" or copy a method from one class onto another class?
Example code:
class A(object):
def foo(self):
print "blah"
class B(object):
foo = A.foo
B().foo()
Expected output:
"blah"
Instead:
TypeError: unbound method foo() must be called with A instance as first argument (got nothing instead)
Use __func__
:
>>> A.foo
<unbound method A.foo>
>>> A.foo.__func__
<function foo at 0x00BC5F70>
>>> class B(object):
... foo = A.foo.__func__
...
>>> B().foo()
"blah"
Quoting the docs:
An instance method object combines a class, a class instance and any callable object (normally a user-defined function).
Special read-only attributes: __self__ is the class instance object, __func__ is the function object; __doc__ is the method’s documentation (same as __func__.__doc__); __name__ is the method name (same as __func__.__name__); __module__ is the name of the module the method was defined in, or None if unavailable.
You can use class inheritance here. Inheritance lets you create an object based on another object, inheriting all of its functions and attributes.
In this case, it looks like:
class A(object):
def foo(self):
print "blah"
class B(A):
# You can add new methods or attributes here,
# or even overwrite those inherited from A if you
# really want to, though you have to be careful with that.
pass
After that declaration,
>>> B().foo()
"blah"
This works because:
A
, and created for it a method foo
.B
inheriting from A
, meaning that when A
"gave birth to it," B
was born with everything that A
has.
B
is an exact copy of A
, since we didn't do anything else to it. However, we could make changes or add more methods.An example:
class A(object):
def foo(self):
print "blah"
class B(A):
def newfoo(self):
print "class A can't do this!"
Which in use, we'd see:
>>> A().foo()
blah
>>> B().foo()
blah
>>> A().newfoo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'newfoo'
>>> B().newfoo()
class A can't do this!
In particular, the reason that your code above didn't work is that when you tried to set B.foo
, you wrote
class B(object):
foo = A.foo
instead of
class B(object):
foo = A().foo
When you wrote A.foo
without the ()
, you were asking for the method straight from the A
type, which wouldn't work in Python. If you were to do foo = A().foo
, what you'd be doing is instantiating an A
object, and then getting a copy of its method foo
, and then assigning it.
The problem here is that it is a bound method you are trying to steal, however, your example does not involve a function that uses instance state (self
). Hence you have two immediate options:
A.foo
a static method (@staticmethod
decorator) functools
.Eg.
import functools
stolen = functools.partial(A.foo, None)
This works because your method does not use instance state, and does not require creating a subclass.
To embellish a bit further, a bound instance method (like A.foo
) expects a bound instance argument (self
, where self is an instance of A
). In normal usage, this first argument is passed automatically:
a = A()
Now:
a.foo()
A.foo(a)
...Are both equivalent. In the first case, the syntax instance.bound_method()
infers InstanceClass.bound_method(instance)
from a lexical viewpoint (instance
resolves to self
). This is why calling A.foo()
will cause an error, since it expects an instance of A
.
What the solution above does is to warp the function into one that passes a None
as the instance, since the instance is never used anyway (there is no state-based logic). In the case of using staticmethod, it removes the 1st implied expected bound instance argument self
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With