I know it's possible to define a function and use it as a method:
def method(*args, **kwargs):
print "%r %r" % (args, kwargs)
class Test(object):
method1 = method
t = Test()
t.method1() # (<__main__.Test object at 0x10705a4d0>,) {}
I'd like to do the same thing with callable objects, like this:
class Method(object):
__call__ = method
class Test(object):
method1 = Method()
However, when I do this, the self
argument of Method.__call__
is the method itself (which is normal), but the self
argument of the Test
instance is lost.
t = Test()
t.method1() # (<__main__.Method object at 0x10703f110>,) {}
Is it possible to have the self
argument passed as the second argument to Method.__call__
?
By wrapping that function method
in a class you are effectively preventing the mechanism that binds an object to a function and thus creates a method. The way this works is that regular python functions are descriptors.
To summarize the docs: When you write the following code:
some_instance.some_function()
The some_function
s __get__
method is called with some_instance
as the first parameter. The __get__
method then returns a bound method object, that remembers the instance. Later, when the bound method object's __call__
method is called, it passes the saved instance as a first parameter.
We can reimplement that behaviour like this:
def method(*args, **kwargs):
print("%r %r" % (args, kwargs))
class BoundMethod(object):
# the bound method remembers the instance and the function
def __init__(self, instance, function):
self.instance = instance
self.function = function
# when the bound method is called, it passes the instance
def __call__(self, *args, **kwargs):
return self.function(self.instance, *args, **kwargs)
class Method(object):
# the __get__ method assembles a bound method consisting of the
# instance it was called from and the function
def __get__(self, instance, cls):
return BoundMethod(instance, method)
class Test(object):
method1 = Method()
t = Test()
t.method1() # (<__main__.Test object at 0x7f94d8c3aad0>,) {}
In your case Method
is not a descriptor. So, when internally the __call__
property (which is a function) is requested it is bound to an object of the containing class (Method
).
I am not sure if this is useful, as this example is just a simplified version of what happens under the hood anyway.
Note: in this example:
class C:
def function(self): pass
print(C.function)
print(C().function)
The first print shows us, that an unbound method literally is called <unbound method C.function>
while a bound method is called <bound method C.function of ...>
.
In python3 however the first print shows us that unbound methods are just the unchanged functions we defined in the class.
Yes: make the method a descriptor—which, as already noted by Wombatz, is the mechanism used by normal method binding.
class Method(object):
def __get__(self,obj,cls):
def method(*args, **kwargs):
print type(obj) # to illustrate what object we get
print type(self) # we have the Method too
print "%r %r" % (args, kwargs)
return method
Notes:
__get__
on a function and produce a legitimate bound method object, but this way you have self
and obj
available.obj
is None
if the method is looked up on the class itself (Test.method1
, rather than Test().method1
); you can decide separately what to do (with cls
) in that case.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