Consideration for Python decorators of the type that passes variables

When developing with Python, I think that there are many cases where you want to put common processing before and after a function. In that case, the decorator (the one that annotates the line above the function) is often used. In this article, I'll look at the basics of using decorators, and later on the types of decorators that allow you to pass variables.


The simplest decorator is implemented as follows:


def decorator(func):
    def decorated(*args, **kwargs):
        print('Decorated start')
        func(*args, **kwargs)
        print('Decorated end')
    return decorated

To actually use this decorator, do the following:


@decorator
def sample(name):
    print('{}Worked.'.format(name))

When this decorated sample function is executed, it will be printed as follows. You can see that the processing is inserted before and after the sample function as expected.

Decorated start
sample worked.
Decorated end

The reason why it works like this is that @ is syntactic sugar. This is because it is actually equivalent to the following code.


def sample(name):
    print('{}Worked.'.format(name))

# @Equivalent to decorator
sample = decorator(sample)

It's relatively easy to understand so far, but I think there are many cases where you get stuck when trying to understand the type of decorator that allows you to pass variables.


def annotation(param):
    print('annotation start')
    
    def decorator(func):
        print('Start decorator')
        print('param:{}'.format(param))
        
        def decorated(*args, **kwargs):
            print('Decorated start')
            print('param:{}'.format(param))
            
            func(*args, **kwargs)
            print('Decorated end')
           
        print('Decorator finished')
        return decorated
    
    print('annotation end')
    return decorator

Considering the movement of syntactic sugar (@) earlier, shouldn't the argument of the top-level function (annotation) have to be a function? It's easy to think, but the code below actually works fine.


print('Define annotated function')

@annotation(param=999)
def sample(name):
    print('{}Worked.'.format(name))
    
print('Execute annotated function')

sample('sample')

The print output is shown below

Define annotated function
annotation start
annotation end
Start decorator
param:999
Decorator finished
Execute annotated function
Decorated start
param:999
sample worked.
Decorated end

Looking at the print output above, from among the decorator functions that are called after the annotation function ends. You can refer to param which is the argument of annotation function. The reason for this behavior is that the variables that the function can refer to are determined when the function is defined, so the decorator function defined in the annotation function can refer to the param that is the argument of the annotation function. Because.

Also, considering the contents of the print output, the syntax sugar (@) of the type of decorator that can pass variables is considered to be equivalent to the following.


def sample(name):
    print('{}Worked.'.format(name))

# @annotation(param=999)Equivalent to
sample = annotation(param=999)(sample)

Reference material

About Python closures: Think about the scope of functions and the fact that functions are first-class citizens

Recommended Posts

Consideration for Python decorators of the type that passes variables
[python] Checking the memory consumption of variables
The story of manipulating python global variables
[python] [meta] Is the type of python a type?
Pandas of the beginner, by the beginner, for the beginner [Python]
The story of low learning costs for Python
Image processing? The story of starting Python for
Code for checking the operation of Python Matplotlib
[Python] Determine the type of iris with SVM
How to find the coefficient of the trendline that passes through the vertices in Python
the zen of Python
[Python] A program that counts the number of valleys
Python program that looks for the same file name
The attitude that programmers should have (The Zen of Python)
[Python] A program that compares the positions of kangaroos.
A python script that generates a sample dataset for checking the operation of a classification tree
A python script that gets the number of jobs for a specified condition from indeed.com
Towards the retirement of Python2
Check the operation of Python for .NET in each environment
Python --Check type of values
Different from the import type of python. from A import B meaning
About the ease of Python
Check the scope of local variables with the Python locals function.
Miscellaneous notes that I tried using python for the matter
[Python] The biggest weakness / disadvantage of Google Colaboratory [For beginners]
Treat the Interface class like that with Python type annotations
What beginners learned from the basics of variables in python
About the features of Python
Google search for the last line of the file in Python
[Data science memorandum] Confirmation of the contents of DataFrame type [python]
A Python script that compares the contents of two directories
The Power of Pandas: Python
A memorandum of understanding for the Python package management tool ez_setup
The story that the version of python 3.7.7 was not adapted to Heroku
How to change the log level of Azure SDK for Python
Wrap (part of) the AtCoder Library in Cython for use in Python
[Python] Organize the basic structure of Flask apps (Aim for de-copying)
A story that struggled to handle the Python package of PocketSphinx
The story of making a standard driver for db with python.
A function that measures the processing time of a method in python
Verification of the theory that "Python and Swift are quite similar"
python note: map -do the same for each element of the list
[python] A note that started to understand the behavior of matplotlib.pyplot
The story of making a module that skips mail with python
[Python] A program that rotates the contents of the list to the left
Initializing global variables using Python decorators
The story of Python and the story of NaN
A good description of Python decorators
First Python 3 ~ The beginning of repetition ~
Python for super beginners Python # dictionary type 1 for super beginners
Existence from the viewpoint of Python
pyenv-change the python version of virtualenv
Change the Python version of Homebrew
About the basic type of Go
This and that of python properties
[Python] Understanding the potential_field_planning of Python Robotics
Review of the basics of Python (FizzBuzz)
See python for the first time
What is the python underscore (_) for?
Master the type with Python [Python 3.9 compatible]
Introductory table of contents for python3