I have (as it seems to me) some basic understanding of Python scoping rules (based on studying of this answer).
I have also learned from the documentation on exec, that it takes globals and locals as optional arguments, and that:
In all cases, if the optional parts are omitted, the code is executed in the current scope.
NOTE: all examples below assume usage of Python 3.
With that said, I have recently stumbled onto the case, which confused me a bit:
def test(passed_data):
local_result = 5
exec("print(passed_data)")
exec("print(local_result)")
return local_result
print (test('whatever'))
running code above results in:
whatever
5
5
Here, it is evident that exec has access to tests locals (passed_data and 'local_result').
Though if we will try to change any of them:
def test(passed_data):
local_result = 5
exec("print(passed_data)")
exec("print(local_result)")
exec("passed_data = 222")
exec("local_result = 111")
exec("print(passed_data)")
exec("print(local_result)")
return local_result
print (test('whatever'))
it will result in:
whatever
5
whatever
5
5
Using global inside exec:
def test(passed_data):
local_result = 5
exec("print(local_result)")
exec("global local_result; local_result = 111")
exec("print(local_result)")
return local_result
print (test('whatever'))
gives the same result (of course, since local_result is local to the scope of test):
5
5
5
What enables us to chance local_result via exec — is defining it using global:
def test(passed_data):
global local_result
local_result = 5
exec("print(local_result)")
exec("global local_result; local_result = 111")
exec("print(local_result)")
return local_result
print (test('whatever'))
This gives us:
5
111
111
It seems to me that I'm just missing some basic understanding of Python scoping or the mechanics of exec, to grasp this case.
Nevertheless, I would like to understand the following:
- Why
execis able to print variable from the function scope, without usingglobal, but is not able to change it? - My understanding is that (given
globalsandlocalsare omitted)execwill execute any Python code, within the scope it is called from, as if this code was just in the source (withoutexec), where (and how) am I wrong in this assumption?
P.S.: I understand that changing local variable via exec is not 'right thing to do', I seek the understanding of exec scoping rules just for the sake of learning.