Python decorators - __call__ in class

I tried to understand Python decorators, and I tried to write an equivalent program for this:

class myDecorator(object): def __init__(self, f): print ("inside myDecorator.__init__()") f() # Prove that function definition has completed def __call__(self): print ("inside myDecorator.__call__()") @myDecorator def aFunction(): print ("inside aFunction()") print ("Finished decorating aFunction()") aFunction() 

The problem is that I do not understand how the class __call__ method is called by calling aFunction() at the end.

Replaced aFunction() with myDecorator.__call__(aFunction) . could you help me? How would an equivalent program without decorators be?

Thanks!

+8
python python-decorators
source share
4 answers

Output your code

 inside myDecorator.__init__() inside aFunction() Finished decorating aFunction() inside myDecorator.__call__() 

First, do you know what this @decorator syntax means?

 @decorator def function(a): pass 

is another way of saying:

 def function(a): pass function = decorator(function) 

So in your case

 @myDecorator def aFunction(): print ("inside aFunction()") 

means just

 def aFunction(): print ("inside aFunction()") aFunction = myDecorator(aFunction) 

First, you basically create a new instance of the myDecorator class by calling its constructor (__init__) and passing it an object to a function function. Then it performs printing and the specified function. Also note that this happens when the function is loaded by the interpreter, and not when it is executed, so if you import something from this file, it will then execute, rather than use or call.

Then, by executing aFunction() , when aFunction is still referencing an instance of myDecorator, it calls the __call__ myDecorator method, which is executed. Note that f() in this case means the same as f.__call__(f) , since the __call__ method __call__ used to enable and override the default behavior of calling objects (in simplification, any object can be called if it has a method __call__ ).

If you want to execute the aFunction function when you call it, you must assign it to the instance variable in __init__ and call it in __call__ myDecorator.

+8
source share

afunction is replaced by an instance of the myDecorator class. The class has a __call__ method, so the instance can be called as a function. Thus, if its signature is compatible (usually the decorator returns something that uses *args and **kwargs ), the instance can be used as a replacement for the original function.

Normally, the __call__ method __call__ call a wrapped function. Doing this in __init__ usually incorrect; __init__ should store the link to the wrapped function as an instance attribute, so __call__ can call it.

+1
source share

So that the whole purpose of the decorator is to replace (or, more often, wrap) the function with the function returned by the decorator. In your case, aFunction is replaced with an instance of myDecorator , so when you call aFunction() you really call that instance: and in Python, calling the class instance calls its __call__ method.

The definition of a decorated function is exactly equivalent to this:

 def aFunction(): print("inside aFunction()") aFunction = myDecorator(aFunction) 

Usually, of course, the wrapper function will call the original function after doing what it does.

+1
source share

Here's the fix:

 class myDecorator(object): def __init__(self, f): print ("inside myDecorator.__init__()") self.f = f #Store the function being wrapped def __call__(self): print ("inside myDecorator.__call__()") self.f() # Call the wrapped function 
+1
source share

All Articles