Python exec

Reference link: Namespace and scope in Python

table of Contents

exec() is simple to use

Dynamically execute simple string code

Dynamically execute more complex code

Execute the Python code in the file

Pass parameters in exec

Problems encountered in use

reference

exec() is simple to use

I personally prefer to use exec() in Python, which can be used to dynamically execute string code. In the for loop, a large number of statements like list1=1, list2=2, list3=3... can be executed quickly, making the code appear More concise.

First, let’s briefly talk about exec(). exec() is a very interesting and practical built-in function. Unlike eval() which can only perform the function of calculating the result of mathematical expressions, exec() can dynamically execute complex Python. The code is powerful, but there are many small places that are easy to step on. The pits are good but not easy to understand. Light and shadow coexist.

Dynamically execute simple string code

Dynamically execute more complex code

func = "def fact(n):\n\treturn 1 if n==1 else n*fact(n-1)"

exec(func)

a = fact(5)

print(a)

Execute the Python code in the file

Store the Python code we want to put in eg.txt

def fact(n):

if n==1:

return 1

else:

return n*fact(n-1)

t = fact(6)

print(t)

Pass parameters in exec

x = 10

expr = """

z = 30

sum = x + y + z

print(sum)

"""

def func():

y = 20

exec(expr)

exec(expr, {'x': 1, 'y': 2})

exec(expr, {'x': 1, 'y': 2}, {'y': 3, 'z': 4})

func()

Problems encountered in use

I have encountered some problems while using it today and simply record it.

def main():

file_list = [2014, 2045, 2065, 2070, 2080, 2110, 2123, 2133]

generate_outliers_analysis_log(file_list, "log/outliers.log")

for file in file_list:

csv_df = csv_file_to_df(r"D:/FTPD/newEnv/" + str(file) + ".csv")

port_suffix = [33, 35, 36, 37, 39, 40]

loc = locals()

for suffix in port_suffix:

Avoid repeated execution of the same statement by executing string code

exec("sorted_df_%s =  get_sorted_port_df(csv_df, '25GE1/0/%s')" % (str(suffix), str(suffix)))

sorted_df_33, sorted_df_35, sorted_df_36 = loc["sorted_df_33"], loc["sorted_df_35"], loc["sorted_df_36"]

sorted_df_37, sorted_df_39, sorted_df_40 = loc["sorted_df_37"], loc["sorted_df_39"], loc["sorted_df_40"]

sorted_df_list = [sorted_df_33, sorted_df_35, sorted_df_36, sorted_df_37, sorted_df_39, sorted_df_40]

name_list = ["25GE1/0/33", "25GE1/0/35", "25GE1/0/36", "25GE1/0/37", "25GE1/0/39", "25GE1/0/40"]

save_port_figure_and_excel(range(1, 7), sorted_df_list, name_list, str(file), 'port_csv/' + str(file) + '.xlsx')

This line of code encountered an error when running:

sorted_df_33, sorted_df_35, sorted_df_36 = loc["sorted_df_33"], loc["sorted_df_35"], loc["sorted_df_36"]

The error message is as follows:

sorted_df_33, sorted_df_35, sorted_df_36 = loc["sorted_df_33"], loc["sorted_df_35"], loc["sorted_df_36"]KeyError: 'sorted_df_33'。

It is strange at first glance. In order to avoid the KeyError problem, exec is often used in conjunction with locals().

First of all, regarding locals, I think there are four points worth noting:

  1. The locals() dictionary is a proxy for the local namespace. It will collect the variables of the local scope. If the local variables are dynamically modified during the code runtime, only the dictionary will be affected, and the real local scope variables will not be affected. 2. When locals() is called again (that is, when locals() is called twice), the content modified dynamically (exec()) will be discarded due to re-collection, and locals() will be refreshed to not contain the previous exec( ) A dictionary of kv pairs after execution. 3. The local namespace at runtime cannot be changed, which means that the variable assignment in the exec() function will not affect it, but the locals() dictionary is variable and will be affected by the exec() function. 4. Since the locals() dictionary is a proxy for the local namespace (dictionary), it will contain all local variables in the current local scope, so when the result of locals() is assigned to a variable, a circular reference will be generated .

What does point 4 mean, give a simple example

def test():

a = 13

loc = locals()

exec('b = a + 1')

b = loc['b']

print(b)

In the above small piece of code, when the line loc = locals() is executed, the loc dictionary will have a key of'loc', which is a key-value pair of the loc dictionary itself.

And this loc is a circular reference, just look at the debug diagram below. Why, because locals() will include all local variables in the current local scope. Since loc itself is also a local variable, it creates a circular reference.

Common pitfalls of exec

https://segmentfault.com/a/1190000019217209

Analysis of the problems encountered

After reading the above linked article, I personally feel that the explanation has been very thorough. Let's look back briefly, that is, for the following example one, a KeyError will be reported, and for the following example two, no error will be reported. This is related to the call location of locals(). Locals() is a copy of the dictionary of local variables. The local namespace (local variable dictionary) at runtime cannot be changed, which means that the variable assignment in the exec() function will not be correct. It has an impact, but the locals() dictionary is variable and will be affected by the exec() function. It means that if we want to get the dynamically executed value in exec later and assign it to a new variable, we need to call locals() before exec, otherwise it cannot be obtained.

Okay, on this basis, let’s review the problem we encountered today. First, simplify the business code that has the above problem to use the exec+locals+placeholder example3 in the example 3 below, and then use the method of example4 to make a simple Verification. Hey, there is an interesting problem here. Logically speaking, in the example3() function, the second line defines loc. The loc here will be modified by exec after the execution of the third line and the fourth line is completed. There must be five keys "a0", "a1", "a2", "a3", and "a4" in loc. This has also been verified in example4, that is, it can be obtained as long as the original variable name is not used. I don’t quite understand why this error occurs. Maybe this is a design problem of exec and placeholders. From this, we can also draw a conclusion. It is recommended not to rewrite the variable values of exec dynamic execution in the code. Name, avoid locating these small and trivial problems to spend more time. :

reference

https://segmentfault.com/a/1190000014581721

https://segmentfault.com/a/1190000019217209

https://python3-cookbook.readthedocs.io/zh_CN/latest/c09/p23_executing_code_with_local_side_effects.html

Recommended Posts

Python exec
Python multithreading
Python CookBook
Python FAQ
Python3 dictionary
Python3 module
python (you-get)
Python string
Python descriptor
Python basics 2
Python notes
Python3 tuple
CentOS + Python3.6+
Python advanced (1)
Python decorator
Python IO
Python multithreading
Python toolchain
Python3 list
Python multitasking-coroutine
Python overview
python introduction
Python analytic
Python basics
07. Python3 functions
Python basics 3
Python multitasking-threads
Python functions
python sys.stdout
python operator
Python entry-3
Centos 7.5 python3.6
Python string
python queue Queue
Python basics 4
Python basics 5
Centos6 install Python2.7.13
Python answers questions
Python basic syntax (1)
Python exit loop
Ubuntu16 upgrade Python3
Centos7 install Python 3.6.
ubuntu18.04 install python2
Python classic algorithm
Relearn ubuntu --python3
Python2.7 [Installation Tutorial]
Python string manipulation
Python 3.9 is here!
Python study notes (1)
python learning route
CentOS7 upgrade python3
Python review one
linux+ubuntu solve python
Functions in python
Python learning-variable types
CentOS install Python 3.6
7 features of Python3.9
ubuntu12.04 install python3
Python - centos6 installation
Centos7 install Python2.7
01. Introduction to Python