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 test
s 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
exec
is able to print variable from the function scope, without usingglobal
, but is not able to change it? - My understanding is that (given
globals
andlocals
are omitted)exec
will 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.