David
David

Reputation: 1494

Confusing python variable scope

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?

Upvotes: 0

Views: 216

Answers (2)

user
user

Reputation: 675

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.

Upvotes: 1

AmphotericLewisAcid
AmphotericLewisAcid

Reputation: 2299

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.

Upvotes: 1

Related Questions