Take the following code:
import something
def Foo():
something = something.SomeClass()
return something
…this is apparently not valid code:
UnboundLocalError: local variable 'something' referenced before assignment
…as the local variable something is created, but not assigned, before the RHS of the = is evaluated. (See, for example, this related answer's comment.) This seems a bit odd to me, but sure, I'll go with it. Now, why is the following valid code?
class Foo(object):
something = something.SomeClass()
My understanding was that the inside of a class definition was essentially a scope:
The class’s suite is then executed in a new execution frame (see section Naming and binding), using a newly created local namespace and the original global namespace.
So, then, why does that code act differently than that of a function?
From the python class documentation:
Class definitions place yet another namespace in the local scope.
A special quirk of Python is that – if no global statement is in effect – assignments to names always go into the innermost scope. Assignments do not copy data — they just bind names to objects. The same is true for deletions: the statement del x removes the binding of x from the namespace referenced by the local scope. In fact, all operations that introduce new names use the local scope: in particular, import statements and function definitions bind the module or function name in the local scope. (The global statement can be used to indicate that particular variables live in the global scope.)
So within a function (or a scope) the assignment creates a local unbound variable that is accessed before it is bound, whereas in a class definition it creates an entry in the "namespace" dictionary of that class on assignment, allowing the resolution of something to the outer namespace (the module namespace).
Consider the following example which may help to clarify this:
import datetime
class Foo(object):
datetime = datetime.datetime
>>> datetime
<module 'datetime' from '/usr/lib/python2.6/lib-dynload/datetime.so'>
>>> Foo.datetime
<type 'datetime.datetime'>
Note that the line datetime = datetime.datetime is actually assigning to the name Foo.datetime, which is not ambiguous with the global datetime (like it would be if the same code were in the function).
In summary, because class definitions create a new namespace as well as a new scope, you are allowed to directly access a name in an enclosing scope and assign to the same name in the local scope.
Related
def decorator(func):
def returning():
var = 1
func()
print(var)
return(returning)
#decorator
def function():
nonlocal var
var = 5
function()
var is declared inside the returning() function before calling func(), yet I get a binding error.
I don't understand why this happens.
Python determines scopes at compile time, making the scope model static, not dynamic. The nonlocal and global statements tell the compiler to alter the scope where a name is set. nonlocal tells the compiler that a given name is to be assigned to as a closure, living in an enclosing scope. See the Naming and binding section of the Python execution model documentation:
If a name is bound in a block, it is a local variable of that block, unless declared as nonlocal or global.
and
Each assignment or import statement occurs within a block defined by a class or function definition or at the module level (the top-level code block).
and
A scope defines the visibility of a name within a block. If a local variable is defined in a block, its scope includes that block. If the definition occurs in a function block, the scope extends to any blocks contained within the defining one, unless a contained block introduces a different binding for the name.
So only function definitions, class definitions and the module level are blocks where assignments take place. nonlocal can only act on names in a nested scope:
The nonlocal statement causes corresponding names to refer to previously bound variables in the nearest enclosing function scope.
function() is not a nested block, there is no enclosing function scope.
Decorators are a runtime feature, and do not produce a new encloding function scope. You didn't nest function() inside the decorator, you only passed in a reference to the function object. The function has already been created, compilation is done and the scope of the names is set in stone.
The only way to do what you want would require re-compilation or bytecode manipulation, both subjects that are very much on the very advanced side of Python hacking.
For example, with access to the source code (usually the case), you could use inspect and ast to merge the abstract syntax tree of function into that of returning to create a nested scope, then compile that new tree into bytecode that would do what you want. Or you'd have to do something similar with the bytecode of both functions to make returning produce a closure, and function() take that closure for the value of var. This would require an intimate knowledge of how Python closures work, and what bytecode the compiler produces to handle closures.
All this means that it would be much easier to find yourself a different approach to your problem. Perhaps use a class with state to alter the state in different contexts, etc.
LISTL = []
VAR1 = 0
def foo():
... VAR1 += 1
... return VAR1
...
On calling foo(), I get this error:
UnboundLocalError: local variable 'VAR1' referenced before assignment
However, consider the list LISTL
>>> def foo(x):
... LISTL.append(x)
... return LISTL
...
>>> foo(5)
[5]
This works as expected. The question is why the append on a list works but I can't change the int?
Also, is this the right way to declare a global in Python? (Right after the import statements)
The reason for this difference has to do with how Python namespaces the names. If you're inside a function definition (def foo():), and you ACCESS a name (VAR1 or LISTL), it will first search your local namespace, where it will find nothing, and then it will search the namespace of the module the function was defined in, all the way up to the global namespace until it finds a match, or fails.
However, ACCESSING a name, and ASSIGNING a name, are two different concepts. If you're again within your function definition, and you say VAR1 = 2, you're declaring a new variable with the new local name VAR1 inside the function. This makes sense if you consider that otherwise you would encounter all sorts of naming collisions if there was no such namespacing at work.
When you append to a list, you are merely ACCESSING the list, and then calling a method on it which happens to change its conceptual value. When you use do +=, you're actually ASSIGNING a value to a name.
If you would like to be able to assign values to names defined outside of the current namespace, you can use the global keyword. In that case, within your function, you would first say global VAR1, and from there the name VAR1 would be the name in the outer namespace, and any assignments to it would take effect outside of the function.
If you assign to a variable within a function, that variable is assumed to be local unless you declare it global.
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?
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.
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.
This question already has answers here:
Using global variables in a function
(25 answers)
Closed 8 months ago.
I'd like to be able to do something like this:
#mymodule
var = None
def load():
var = something()
Other module(s):
#secondmodule
import mymodule
mymodule.load()
#thirdmodule
from mymodule import var
print var #Shouldn't be None
But I don't know how to reference a modules variable from a function defined in the module.
Is this possible? Or am I going to need to put a global declaration in every place I wan't to use this.
Or am I going at this completely wrong?
Just change the function definition to:
def load():
global var # this line has been added to the original code
var = something()
Global variables are read-only from sibling methods. More accurately unless a variable is specified as global, Python consider it as local, but a read access to a local variable name will reach module-level scope if the name is not present in local scope.
See also use of “global” keyword in python and the doc for more details about the global statement
You seem to mostly have it. You are missing only the fact that "module-level" variables are called global in Python. (They are not truly global, but only global to the module they are declared in, in other words.)
In any function where you modify a global variable (you want to make the name refer to a different object), it must be declared global. So your load() function needs a global var at the beginning. If you are only using the value of a global variable, or if it is a mutable type such as a list and you are modifying it, but not changing the object that the name points to, you needn't declare it global.
The import statement is, as you have discovered, how you can import a module-level variable from one module into another.
LISTL = []
VAR1 = 0
def foo():
... VAR1 += 1
... return VAR1
...
On calling foo(), I get this error:
UnboundLocalError: local variable 'VAR1' referenced before assignment
However, consider the list LISTL
>>> def foo(x):
... LISTL.append(x)
... return LISTL
...
>>> foo(5)
[5]
This works as expected. The question is why the append on a list works but I can't change the int?
Also, is this the right way to declare a global in Python? (Right after the import statements)
The reason for this difference has to do with how Python namespaces the names. If you're inside a function definition (def foo():), and you ACCESS a name (VAR1 or LISTL), it will first search your local namespace, where it will find nothing, and then it will search the namespace of the module the function was defined in, all the way up to the global namespace until it finds a match, or fails.
However, ACCESSING a name, and ASSIGNING a name, are two different concepts. If you're again within your function definition, and you say VAR1 = 2, you're declaring a new variable with the new local name VAR1 inside the function. This makes sense if you consider that otherwise you would encounter all sorts of naming collisions if there was no such namespacing at work.
When you append to a list, you are merely ACCESSING the list, and then calling a method on it which happens to change its conceptual value. When you use do +=, you're actually ASSIGNING a value to a name.
If you would like to be able to assign values to names defined outside of the current namespace, you can use the global keyword. In that case, within your function, you would first say global VAR1, and from there the name VAR1 would be the name in the outer namespace, and any assignments to it would take effect outside of the function.
If you assign to a variable within a function, that variable is assumed to be local unless you declare it global.