python method stealer
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:
- You created class
A
, and created for it a methodfoo
. - You created class
B
inheriting fromA
, meaning that whenA
"gave birth to it,"B
was born with everything thatA
has.- In our case,
B
is an exact copy ofA
, since we didn't do anything else to it. However, we could make changes or add more methods.
- In our case,
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:
- Make the definition of
A.foo
a static method (@staticmethod
decorator) - Decorate or wrap the function to pass an unused argument. E.g. using
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
.