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:
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:
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