I usually don't think too hard about variable scope in python, but I wanted to see if there's a clean explanation for this. Given two files called main.py
and utils.py
:
utils.py
def run():
print(L)
main.py
import utils
def run():
print(L)
if __name__ == '__main__':
L = [1,2]
run()
utils.run()
The first run()
call in main.py
runs fine despite L
not being fed into run()
, and the utils.run()
call raises a NameError
. Is L
a global variable available to all functions defined in main.py
?
If I imported utils
with from utils import *
instead of import utils
, would that change anything?
2 Answers 2
It's module-level scope. A global variable defined in a module is available to all functions defined in the same module (if it's not overriden). Functions in another module don't have access to another module's variables unless they import them.
About "If I imported utils with from utils import * instead of import utils, would that change anything?": No. The scope is determined at parsing time.
Check this for more information.
Notably:
It is important to realize that scopes are determined textually: the global scope of a function defined in a module is that module’s namespace, no matter from where or by what alias the function is called. On the other hand, the actual search for names is done dynamically, at run time [...]
So the global scopes of both functions for variables defined in a module are the modules they're defined in. For one, its module also later has a definition for a global variable it uses, but not the other module, and when it's time to check for a variable when a function is run, each checks their own module's variables definitions, one finds it, the other does not.
Comments
See Python's FAQ. Their implementation of scope is a compromise between convenience and the dangers of globals.
Variables are treated as globals if they're only referenced by a function, and need to be explicitly declared as globals (e.g. global foo
) inside of the function body if you want to edit them. If you edit run()
to try and change the value of L, you'll get an error.
What's happening here is that your Python code imports utils, and then runs run()
. This function sees that you're looking for a variable named "L," and checks your global namespace.
2 Comments
if __name__ == '__main__':
block is not inside a function. Usually people define a function like def main()
and then just put a call to main()
in their __main__
block. So anything you declare in it is obviously global. If you call utils.run()
before defining L
then you'll get an error, but if you do it after then L
will be defined so there will be no error.__name__ == '__main__'
block defines them as globals to the module. I now clearly understand the need for putting a main()
function call inside the __main__
block. Thanks!