Initializing global variables using Python decorators

Introduction

When I was looking at the pip repository on github, I found that I was using an interesting decorator, so I will share it.

TL;DR --Decorators can be used not only to qualify a function, but also to ** execute a function **. -[Main subject](Execute the function inside the #decorator)

Global variable value when imported

First of all, what value do global variables take when importing the following packages? Both the functions spam and ʻegg are functions only for updating the global variable global_variable`.

mypackage/__init__.py


GLOBAL_VARIABLE = 0

def spam():
    global_variable = 1
    globals().update(locals())

def egg():
    global global_variable
    global_variable = 2

main.py


import mypackage
if __name__ == "__main__":
    print(mypackage.global_variable)

The value of global_variable hasn't changed since it was declared, because we're just defining the function and not executing it. Of course, the execution result is as follows.

$python3 main.py
0

So what if you try calling the function at the end of mypackage / __ init__.py?

mypackage/__init__.py


GLOBAL_VARIABLE = 0

def spam():
    global_variable = 1
    globals().update(locals())

def egg():
    global global_variable
    global_variable = 2

spam()
egg()

In this case, the function is called and the value of global_variable is overwritten in both spam and ʻegg`, so the execution result is as follows.

$python3 main.py
2

However, with this method, if the number of functions you want to execute increases, you have to write the code to call that much, which is troublesome. That's where the ** decorator ** comes in.

Execute the function inside the decorator

Here is the main issue. Let's take a look at the code. Consider the following call_aside function.

mypackage/__init__.py


global_variable = 0

def call_aside(f, *args, **kwargs):
    f(*args, **kwargs)
    return f

@call_aside
def spam():
    global_variable = 1
    globals().update(locals())

@call_aside
def egg():
    global global_variable
    global_variable = 2

main.py


import mypackage
if __name__ == "__main__":
    print(mypackage.global_variable)

What the execution result is

$python3 main.py
2

It looks like! At first, I didn't understand the reason for this, so I was quite worried. However, the mechanism is simple once you understand it. Focusing on the call_aside function,

def call_aside(f, *args, **kwargs):
    f(*args, **kwargs) # <- execute f
    return f

And so on, the function is called internally. Therefore, just by qualifying with call_aside, spam and ʻegg will be executed when mypackage is imported, so the value of global_variable` has changed as shown above. In this case, even if the number of functions you want to execute at the time of import increases, you only have to decorate it: tada:

Supplement

When examining Python decorators, many explain that decorators are used to ** "add processing before and after a function" and "return a function with processing added before and after" **. I think.

def decorator(f):
  def wrapper(*args, **kwargs):  
    print("Preprocessing")
    f(*args, **kwargs)
    print("Post-processing")
  return wrapper

In this way, the wrapper function is just defined and not executed. Decorating a function with this decorator has no effect, such as updating the value of a global variable, until you call the decorated function.

reference

pypa/pip/blob/master/src/pip/_vendor/pkg_resources/__init__.py

Finally

If you can read and write Python to some extent, take a look at official github such as CPython and Pypa. There are an infinite number of chords for the chords, so I think there will be new discoveries and helpful codes.

Recommended Posts

Initializing global variables using Python decorators
Using global variables in python functions
Python notes using perl-special variables
# 1 [python3] Simple calculation using variables
[Python] Variables
[Python3] Dynamically define global variables in functions
The story of manipulating python global variables
Start using Python
About python decorators
About Python decorators
Scraping using Python
Practice applying functions and global variables in Python
Overthrow, Python Global Declaration
[Python] Get environment variables
Global and local variables 2
Operate Redmine using Python Redmine
Fibonacci sequence using Python
Data analysis using Python 0
Data cleaning using Python
Using Python #external packages
WiringPi-SPI communication using Python
Age calculation using python
Search Twitter using Python
Name identification using python
Notes using Python subprocesses
Try using Tweepy [Python2.7]
Global and local variables 1
Consideration for Python decorators of the type that passes variables
Python notes using perl-ternary operator
Flatten using Python yield from
Save images using python3 requests
Python: Class and instance variables
[S3] CRUD with S3 using Python [Python]
[Python] Try using Tkinter's canvas
About Python variables and objects
Record global IP with python
Using Quaternion with Python ~ numpy-quaternion ~
Try using Kubernetes Client -Python-
[Python] Using OpenCV with Python (Basic)
Scraping using Python 3.5 Async syntax
Website change monitoring using python
Handle environment variables in Python
Post to Twitter using Python
Start to Selenium using python
Search algorithm using word2vec [python]
Change python version using pyenv
python: Basics of using scikit-learn ①
Create JIRA tickets using Python
Python class variables and instance variables
Instrument control using Python [pyvisa]
Manipulate spreadsheets locally using Python
Python memo using perl --join
Web scraping using Selenium (Python)
Python Beginner's Guide (Variables / Arrays)
[Python] I tried using OpenPose
[Python] JSON validation using Voluptuous
Python variables and object IDs
Declaration of C global variables
Broadcast on LINE using python
Data analysis using python pandas
Translate using googletrans in Python