It seems that there are two things that are not being distinguished in some guides about this.
When a function is running, there is its local scope, and some scopes above her on call stack. Each scope has its local variables.
When a function is defined, there is also a call stack with scopes.
So when we reference a variable in the function, its name is resolved via rule LEGB. Does that rule apply to call stack of when it was defined, or the current call stack when it is running? I think it's the first one:
def f():
y = 'when_defined'
def g():
print(y)
return g
def h(g):
y = 'when_running'
g()
g = f()
h(g)
>>> when_defined
But in case when it comes to global variables, they don't have to be defined when the function is being defined, and can still be looked up
def h():
print(x)
x = 1
h()
>>> 1
So my understanding is:
When the function is defined, it decides for itself which of used in it variables are local (namely if they are write-encountered in the code, or are in args), which of the other ones are from enclosed scopes (and save an object for those names in
fun.__closure__
). Other variables don't get a classification (but can then only be looked up in global or builtins). Operatorsnonlocal
,global
force the type of variable they are used on to be "first possible from EGB", and "global", respectvely.When the function is running, and resolving a read on variable name, it first looks if it is a "local"-classified variable or not. If it is, it gives it from
locals()
(and fails if it wasn't assigned yet). Otherwise if it is "enclosed", gives the value fromfun.__closure__
. Then, it looks for it inglobals()
. And if its not there, inbuiltins()
.
Is this understanding correct? Could you give me a place where I can look for the exact behaviour of this?
Is it also true that when doing an import
, we are running a new module, so it can't be referencing anything above in the call stack, because its definition basically has no upper context? And we can simply say that it runs on its own, and then import
adds its locals()
to our locals()
?