Python : Why is it said that variables that are only referenced are implicitly global?

StackOverflow https://stackoverflow.com/questions/23458854

  •  15-07-2023
  •  | 
  •  

Pregunta

From the Python FAQ, we can read :

In Python, variables that are only referenced inside a function are implicitly global

And from the Python Tutorial on defining functions, we can read :

The execution of a function introduces a new symbol table used for the local variables of the function. More precisely, all variable assignments in a function store the value in the local symbol table; whereas variable references first look in the local symbol table, then in the local symbol tables of enclosing functions, then in the global symbol table, and finally in the table of built-in names

Now I perfectly understand the tutorial statements, but then saying that variables that are only referenced inside a function are implicitly global seems pretty vague to me.

Why saying that they are implicitly global if we actually start looking at the local symbol tables, and then follow with the more 'general' ones? Is it just a way of saying that if you're only going to reference a variable within a function, you don't need to worry if it's either local or global?

¿Fue útil?

Solución

Examples

(See further down for a summary)

What this means is that if a variable is never assigned to in a function's body, then it will be treated as global.

This explains why the following works (a is treated as global):

a = 1

def fn():
    print a  # This is "referencing a variable" == "reading its value"

# Prints: 1

However, if the variable is assigned to somewhere in the function's body, then it will be treated as local for the entire function body .

This includes statements that are found before it is assigned to (see the example below).

This explains why the following does not work. Here, a is treated as local,

a = 1

def fn():
    print a 
    a = 2  # <<< We're adding this

fn()

# Throws: UnboundLocalError: local variable 'a' referenced before assignment

You can have Python treat a variable as global with the statement global a. If you do so, then the variable will be treated as global, again for the entire function body.

a = 1

def fn():
   global a  # <<< We're adding this
   print a
   a = 2

fn()
print a

# Prints: 1
# Then, prints: 2 (a changed in the global scope too)

Summary

Unlike what you might expect, Python will not fall back to the global scope it if fails to find a in the local scope.

This means that a variable is either local or global for the entire function body: it can't be global and then become local.

Now, as to whether a variable is treated as local or global, Python follows the following rule. Variables are:

  • Global if only referenced and never assigned to
  • Global if the global statement is used
  • Local if the variable is assigned to at least once (and global was not used)

Further notes

In fact, "implicitly global" doesn't really mean global. Here's a better way to think about it:

  • "local" means "somewhere inside the function"
  • "global" really means "somewhere outside the function"

So, if a variable is "implicitly global" (== "outside the function"), then its "enclosing scope" will be looked up first:

a = 25

def enclosing():
   a = 2
   def enclosed():
       print a
   enclosed()

enclosing()

# Prints 2, as supplied in the enclosing scope, instead of 25 (found in the global scope)

Now, as usual, global lets you reference the global scope.

a = 25

def enclosing():
   a = 2
   def enclosed():
       global a  # <<< We're adding this
       print a
   enclosed()

enclosing()

# Prints 25, as supplied in the global scope

Now, if you needed to assign to a in enclosed, and wanted a's value to be changed in enclosing's scope, but not in the global scope, then you would need nonlocal, which is new in Python 3. In Python 2, you can't.

Otros consejos

Python’s name-resolution scheme is sometimes called the LEGB rule, after the scope names.

When you use an unqualified name inside a function, Python searches up to four scopes—the local (L) scope, then the local scopes of any enclosing (E) defs and lambdas, then the global (G) scope, and then the built-in (B) scope—and stops at the first place the name is found. If the name is not found during this search, Python reports an error.

  • Name assignments create or change local names by default.
  • Name references search at most four scopes: local, then enclosing functions (if any), then global, then built-in.
  • Names declared in global and nonlocal statements map assigned names to enclosing module and function scopes, respectively.

In other words, all names assigned inside a function def statement (or a lambda) are locals by default. Functions can freely use names assigned in syntactically enclosing functions and the global scope, but they must declare such nonlocals and globals in order to change them.

Reference: http://goo.gl/woLW0F

This is confusing and the documentation could stand to be more clear.

"referenced" in this context means that a name is not assigned to but simply read from. So for instance while a = 1 is assignment to a, print(a) (Python 3 syntax) is referencing a without any assignment.

If you reference a as above without any assignment, then the Python interpreter searches the parent namespace of the current namespace, recursively until it reaches the global namespace.

On the other hand, if you assign to a variable, that variable is only defined inside the local namespace unless declared otherwise with the global keyword. So a = 1 creates a new name, a, inside the local namespace. This takes precedence over any other variable named a in higher namespaces.

Unlike some other languages, Python does not look up a variable name in a local symbol table and then fall back to looking for it in a larger scope if it's not found there. Variables are determined to be local at compile time, not at runtime, by being assigned to (including being passed in as a parameter). Any name that is not assigned to (and not explicitly declared global) is considered global and will only be looked for in the global namespace. This allows Python to optimize local variable access (using the LOAD_FAST bytecode), which is why locals are faster.

There are some wrinkles involving closures (and in Python 3, nonlocal) but that's the general case.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top