How does Python know which argument will be original function in decorators?

Stack Overflow Asked on January 5, 2022

I am new to the more advanced features of Python like decorators.

I am unable to understand how the Python interpreter actually understands where to put the original function object in a decorator.

Lets look at an example: Examples taken from here.

Simple decorator with no arguments:

def call_counter(func):
    def helper(*args, **kwargs):
        helper.calls += 1
        return func(*args, **kwargs)
    helper.calls = 0

    return helper

def succ(x):
    return x + 1

This makes perfect sense if we can assume that the first/only argument to the decorator call_counter(func) is the function object that needs to wrapped ie. in this case succ() function.

But things become inconsistent when you are talking about "decorators with parameters". Look at the example below:

Decorator with one argument:

def greeting(expr): # Shouldn't expr be the function here ? Or at least isn't there suppose to be another parameter.
    def greeting_decorator(func): # How does Python know to pass the function down here ?
        def function_wrapper(x):
            print(expr + ", " + func.__name__ + " returns:")
        return function_wrapper
    return greeting_decorator

def foo(x):


Now we know Python has no concept of data-types, so function parameters give no information about what type of object they will contain.

Am I correct ?

Having said that lets look at the line from the above example:

def greeting(expr):

If for decorators the first argument is the function to be wrapped then by that logic expr should point to foo() right ? Otherwise there should be at least two parameters in greeting(), like:

def greeting(func, expr):

But instead Python can "magically" understand that the inner function needs to be passed the function reference:

def greeting(expr): 
    def greeting_decorator(func): # How is it correctly put one level down ?

The code has no datatypes or type information specified, so how is it that for decorators without arguments the function is passed as the first argument and for decorators with arguments the function is passed to the inner function ?

How can the interpreter detect that ?

What is going on here ?

This seems like "magic" to me.

What happens if I have 5 or 6 levels of nested functions ?

I am pretty sure I am missing something pretty basic here.


One Answer

Python evaluates the expression after the @ and uses the result as the decorator function.

Python calls the __call__ method of the object that is the decorator with the function as argument.


def succ(x):
    return x + 1

callcounter is the object looked for __call__ to give the argument func

If you use

def foo(x):

greeting("Hello") is evaluated and its result is an object that Python uses the __call__ method with the func argument.

Answered by rioV8 on January 5, 2022

Add your own answers!

Related Questions

Choice on a list affects the following duplicated list

0  Asked on December 11, 2021 by mrtsm


How can I change server in spring boot application?

4  Asked on December 11, 2021 by vikram-shekhawat


How to modify ggplot2 legend keys?

3  Asked on December 11, 2021 by philippe-massicotte


Split JSON to multiple Objects

2  Asked on December 11, 2021 by marcio-lino


Angular/Typescript Text with routerLink

2  Asked on December 11, 2021 by dotnet


How to use multiple factors in na.aggregate() from zoo package

1  Asked on December 11, 2021 by shadrack-kibet


Ask a Question

Get help from others!

© 2023 All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP