How can a monkey fix the `__call__` method?

It seems I cannot use the monkey patch a __call__ class instance method (and yes, I want to fix only individual instances, not all).

The following code:

 class A(object): def test(self): return "TEST" def __call__(self): return "EXAMPLE" a = A() print("call method: {0}".format(a.__call__)) print("test method: {0}".format(a.test)) a.__call__ = lambda : "example" a.test = lambda : "test" print("call method: {0}".format(a.__call__)) print("test method: {0}".format(a.test)) print(a()) print("Explicit call: {0}".format(a.__call__())) print(a.test()) 

Outputs the following:

 call method: <bound method A.__call__ of <__main__.A object at 0x7f3f2d60b6a0>> test method: <bound method A.test of <__main__.A object at 0x7f3f2d60b6a0>> call method: <function <lambda> at 0x7f3f2ef4ef28> test method: <function <lambda> at 0x7f3f2d5f8f28> EXAMPLE Explicit call: example test 

For now, I want it to output:

 ... example Explicit call: example test 

How to make monkeypatch __call__() ? Why can't I fix it the way I fix other methods?

While this answer tells how to do it (presumably, I have not tested it yet), it does not explain why part of the question.

+5
source share
2 answers

So, as JJ Hakala commented on what Python really does, call this:

 type(a).__call__(a) 

as such, if I want to override the __call__ method, I have to override the __call__ class, but if I don't want to influence the behavior of other instances of the same class, I need to create a new class using the overriden __call__ method.

So, an example __call__ override would look like this:

 class A(object): def test(self): return "TEST" def __call__(self): return "EXAMPLE" def patch_call(instance, func): class _(type(instance)): def __call__(self, *arg, **kwarg): return func(*arg, **kwarg) instance.__class__ = _ a = A() print("call method: {0}".format(a.__call__)) print("test method: {0}".format(a.test)) patch_call(a, lambda : "example") a.test = lambda : "test" print("call method: {0}".format(a.__call__)) print("test method: {0}".format(a.test)) print("{0}".format(a())) print("Explicit a.__call__: {0}".format(a.__call__())) print("{0}".format(a.test())) print("Check instance of a: {0}".format(isinstance(a, A))) 

Running it produces the following output:

 call method: <bound method A.__call__ of <__main__.A object at 0x7f404217a5f8>> test method: <bound method A.test of <__main__.A object at 0x7f404217a5f8>> call method: <bound method patch_call.<locals>._.__call__ of <__main__.patch_call.<locals>._ object at 0x7f404217a5f8>> test method: <function <lambda> at 0x7f404216d048> example Explicit a.__call__: example test Check instance of a: True 
+4
source

For custom classes, it is guaranteed that implicit calls to special methods will work correctly if they are defined in the type of objects, and not in the dictionary of object instances. This behavior causes the following code to throw an exception:

 >>> class C: ... pass ... >>> c = C() >>> c.__len__ = lambda: 5 >>> len(c) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: object of type 'C' has no len() 

Source: https://docs.python.org/3/reference/datamodel.html#special-lookup

+3
source

All Articles