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_functions __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