Python3: exec in global vs local scope
Today, I encountered a seemingly strange problem.
When using exec
to execute a command that you do not want to implement hard into your
code, everything works fine and as expected in a global scope.
That means, if you execute the exec
command in the global part of a script
or hack it into your favourite CLI, the following code behaves as expected.
>>> import pandas as pd
>>> df = pd.DataFrame({"a": [1,2,3,4], "b":[4,3,2,1]})
>>> print(df)
a b
0 1 4
1 2 3
2 3 2
3 4 1
>>> exec('df=df[df["b"] > 2]')
>>> print(df)
a b
0 1 4
1 2 3
The exec
command evaluates the filter expression and assigns its value to df
again.
So far, so good.
However, if you now move the exec
command to a local scope, i.e. inside a function,
it suddenly ceases to yield the expected result.
>>> import pandas as pd
>>> def lol(df):
... exec('df=df[df["b"] > 2]')
... return df
>>> df = pd.DataFrame({"a": [1,2,3,4], "b":[4,3,2,1]})
>>> print(df)
a b
0 1 4
1 2 3
2 3 2
3 4 1
>>> print(lol(df))
a b
0 1 4
1 2 3
2 3 2
3 4 1
Obviously, I cannot overwrite the df
variable here.
On the other hand, it is however perfectly possible to create new variables in the local scope:
>>> def some_method():
... print(locals())
... exec("never_before_seen_variable = 5")
... print(locals())
...
>>> some_method()
{}
{'never_before_seen_variable': 5}
As a side note: It generally is not a good idea to use exec
anywhere in your code
as it can and will introduce unforeseen and unwanted side effects.
For example, the code above will not fail since the variable assignment is a perfectly
valid expression.
However, it does not have the desired effect (to be fair, it does not have any effect).
Additionally, exec
can execute arbitrary code and whole code blocks.
If you don't know exactly who will be using your code (and as a consequence, will have
access to your exec
statement), better leave it out.