Does UnboundLocalError occur only when we try to use assignment operators (e.g. x += 5) on a non-local variable inside a function or there other cases? I tried using methods and functions (e.g. print) and it worked. I also tried to define a local variable (y) using a global variable (x)
(y = x + 5) and it worked too.
Yes - the presence of the assignment operator is what creates a new variable (of the same name) in the current scope. Calling mutating methods on the old object are not a problem, nor is doing something with that old value, since there's no question (if only a single assignment was ever used) which value you're talking about.
The concern here is not the modification of a value. The concern is the ambiguity of the variable used. This can also be solved using the global keyword, which specifically tells Python to use the global version, eliminating the ambiguity.
Remember also that Python variables (or globals) are sort of hoisted, like in JavaScript. Any variable used inside a specific scope is a variable in that scope from the beginning of that scope. That means a variable used inside a function is a variable in that scope from the start of the function, regardless of if it shows up half way through.
A really good reference for this is here. Some more specifics here.
Related
In the code below:
def f():
a = 'x'
def g():
print(a)
if a == 'x':
return True
return False
def h():
print(a)
def i():
a = a + a
return a
a = i()
return a
if g():
return h()
Why is a accessible in function g, but not in function h or i?
I don't want to use nonlocal since I don't want to modify a in any of the inner functions, however I don't see why a itself is not accessible.
Short answer: because you assigned to a (by writing a = a + a and a = i()), you created local variables. The fact that you use variables before assignment does not matter.
Python checks the scope by checking assignments. If you somewhere write an assignment like a =, a +=, etc. regardless where you write it in the function, the function sees a as a local scope variable.
So in case you write:
a = 2
def f():
print(a)
a = 3
Even if you access a before you assign to a, it will still see a as a local variable. Python does not do codepath analysis here.
it sees a a a local variable in f. It will error if you call f(), since it will say you fetch a before it is actually assigned.
In case a variable is not defined locally, Python will iteratively inspect the outer scopes until it finds an a.
The only ways to access a variable from an outer scope if you assign to in a scope is by working with nonlocal or global (or of course passing it as a parameter).
The other answer is great for explaining what's going wrong. I'm adding my own answer to try to explain some of the reasons behind the issue (i.e. the "why" rather the "what").
First you need to understand Python's architecture a little bit. We often describe Python as an "interpreted" language rather than a "compiled" language like C, but that's not really the whole story. While Python doesn't compile directly to machine code, the interpreter doesn't run on the raw source code when the program is running. Rather, there's an intermediate step where the source code is compiled to to bytecode. The compiling happens automatically when a module is loaded, so you may not even be aware of it (though you may have seen the .pyc files that the compiler writes to cache the bytecode).
Anyway, to get back to your scope issue: Python's compiler uses a bytecode instruction to tell the interpreter to access a local variable rather than it uses for accessing a global variable (and third different instruction is sued for to accessing a variable from an enclosing function's scope). Since the bytecode is written by the compiler, the bytecode instruction to use needs to be decided at a function's compile time, not when the function is called. The choice of instruction is tricky though for ambiguous code like this:
a = 1
def foo():
if bar():
a = 2
print(a)
Does the access of a for the print call use the bytecode instruction that reads the global variable a or the instruction that accesses the local variable a? There's no way for the compiler to know in advance if bar will return a true value or not, so there's no possible answer that will let the function work in all situations.
To avoid ambiguity, Python's designers chose that the scope of a variable should be constant throughout each function (so the compiler can just pick one bytecode instruction and stick with it). That is, a name like a can refer to local or a global (or a closure cell) but only one of those in any given function.
The compiler defaults to using local variables (which are the fastest to access) for any name used as the target of an assignment anywhere in the function's code. Since inner functions are compiled at the same time as the functions that contain them, non-local lookups can also be detected at compile time and the appropriate instruction used. If the name isn't found in either the local or the enclosing scopes, the compiler assumes it is a global variable (which doesn't need to be defined yet). The global and nonlocal statements allow you to explicitly tell the compiler to use a specific scope (overriding what it would pick on its own).
You can explore the different ways the compiler handles variable lookups in different scopes using the dis module from the standard library. The dis module disassembles bytecode into a more readable format. Try calling dis.dis on functions like these:
a = 1
def load_global():
print(a) # access the global variable "a"
def load_fast():
a = 2
print(a) # access the local variable "a", which shadows the global variable
def closure():
a = 2
def load_dref():
print(a) # access the variable "a" from the enclosing scope
return load_dref
load_dref = closure() # both dis.dis(closure) and dis.dis(load_dref) are interesting
The full details of how to interpret the output of dis.dis are beyond the scope (no pun intended) of this answer, but the main things to look for are the LOAD_... bytecode instructions that deal with (a) as their target. You'll see three different LOAD_... instructions in the different functions above, corresponding to the three different kinds of scopes they're reading from (each function is named for the corresponding instruction).
This question already has answers here:
Short description of the scoping rules?
(9 answers)
Closed 5 months ago.
I'm a Python beginner and I am from C/C++ background. I'm using Python 2.7.
I read this article: A Beginner’s Guide to Python’s Namespaces, Scope Resolution, and the LEGB Rule, and I think I have some understanding of Python's these technologies.
Today I realized that I can write Python code like this:
if condition_1:
var_x = some_value
else:
var_x = another_value
print var_x
That is, var_x is still accessible even it is not define before the if. Because I am from C/C++ background, this is something new to me, as in C/C++, var_x are defined in the scope enclosed by if and else, therefore you cannot access it any more unless you define var_x before if.
I've tried to search the answers on Google but because I'm still new to Python, I don't even know where to start and what keywords I should use.
My guess is that, in Python, if does not create new scope. All the variables that are newly defined in if are just in the scope that if resides in and this is why the variable is still accessible after the if. However, if var_x, in the example above, is only defined in if but not in else, a warning will be issued to say that the print var_x may reference to a variable that may not be defined.
I have some confidence in my own understanding. However, could somebody help correct me if I'm wrong somewhere, or give me a link of the document that discusses about this??
Thanks.
My guess is that, in Python, if does not create new scope. All the variables that are newly defined in if are just in the scope that if resides in and this is why the variable is still accessible after the if.
That is correct. In Python, namespaces, that essentially decide about the variable scopes, are only created for modules, and functions (including methods; basically any def). So everything that happens within a function (and not in a sub-function) is placed in the same namespace.
It’s important to know however that the mere existance of an assignment within a function will reserve a name in the local namespace. This makes for some interesting situations:
def outer ():
x = 5
def inner ():
print(x)
# x = 10
inner()
outer()
In the code above, with that line commented out, the code will print 5 as you may expect. That’s because inner will look in the outer scope for the name x. If you add the line x = 10 though, the name x will be local to inner, so the earlier look up to x will look in the local namespace of inner. But since it hasn’t been assigned yet, you will receive an UnboundLocalError (“local variable 'x' referenced before assignment”). The nonlocal statement was added in Python 3 to overcome one issue from this: The situation where you want to actually modify the x of the outer scope within the inner function.
For more information on name lookup, see this related question.
This question already has answers here:
Short description of the scoping rules?
(9 answers)
Closed 8 years ago.
>>> a = 10
>>> def f(x):
return x + a
>>> a = 3
>>> f(1)
According to my experience on Java, the definition of f contains a local variable a, but how could the global binding a been visible on the function f call stack environment?
I did a research on the python syntax and found that's true, could anybody offer some background on why python dealing variable scope this way? thanks.
Your function call is in the last line.
When the function gets called, python first looks up for local variables with name a,
if not found, it goes into global scope, and in global scope, the last assigned value of a is 3 ( just before the function was called)
What you may find even stranger is that this will also work:
>>> def f(x):
return x + a
>>> a = 3
>>> f(1)
Note that a hasn't even been defined before the function f. It still works because your call to f is after a is defined and placed in the global namespace. At that point, since f does not have a in its local namespace, it will fetch it from the global namespace.
You can fetch the contents of the global namespace and check for yourself with globals(), and the local namespace with locals(). There's also some neat tricks you can do by manipulating the namespaces directly, but that is in most cases considered bad coding practice in Python, unless you really have a compelling reason and know what you're doing.
It would return 4 because you declare a and f(x) a function then you give valuea=3 and then you give x=1 so the function would return 3+1 which is 4
Python decide variable scope in function based on where they have been assigned. As you didn't assigned variable 'a' inside function so it starts looking out and consider the global value.
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a new value anywhere within the function’s body, it’s assumed to be a local. If a variable is ever assigned a new value inside the function, the variable is implicitly local, and you need to explicitly declare it as global.
Ref : http://effbot.org/pyfaq/what-are-the-rules-for-local-and-global-variables-in-python.htm
Java is a purely object-oriented language, while Python is not. Python supports both structural as well as object-oriented paradigms.
Global variables are part of the structural programming paradigm. So global variables will be available in the scope of a function, unless another variable with exactly the same name exists in the local scope of that function.
If a function needs to modify a variable declared in global scope, it need to use the global declaration. However, if the function just needs to read a global variable it can do so without using a global declaration:
X = 10
def foo():
global X
X = 20 # Needs global declaration
def bar():
print( X ) # Does not need global
My question is about the design of Python: why is Python designed to allow the read of global variables without using the global declaration? That is, why only force assignment to have global, why not force global upon reads too? (That would make it even and elegant.)
Note: I can see that there is no ambiguity while reading, but while assigning it is not clear if one intends to create a new local variable or assign to the global one. But, I am hoping there is a better reason or intention to this uneven design choice by the BDFL.
With nested scopes, the variable lookups are easy. They occur in a chain starting with locals, through enclosing defs, to module globals, and then builtins. The rule is the first match found wins. Accordingly, you don't need a "global" declaration for lookups.
In contrast, with writes you need to specify which scope to write to. There is otherwise no way to determine whether "x = 10" in function would mean "write to a local namespace" or "write to a global namespace."
Executive summary, with write you have a choice of namespace, but with lookups the first-found rule suffices. Hope this helps :-)
Edit: Yes, it is this way "because the BDFL said so", but it isn't unusual in other languages without type declarations to have a first-found rule for lookups and to only require a modifier for nonlocal writes. When you think about it, those two rules lead to very clean code since the scope modifiers are only needed in the least common case (nonlocal writes).
Look at this code:
from module import function
def foo(x):
return function(x)
The name function here is a global. It would get awfully tedious if I had to say global function to get this code to work.
Before you say that your X and my function are different (because one is a variable and the other is an imported function), remember that all names in Python are treated the same: when used, their value is looked up in the scope hierarchy. If you needed global X then you'd need global function. Ick.
Because explicit is better than implicit.
There's no ambiguity when you read a variable. You always get the first one found when searching scopes up from local until global.
When you assign, there's only two scopes the interpreter may unequivocally assume you are assigning to: local and global. Since assigning to local is the most common case and assigning to global is actually discouraged, it's the default. To assign to global you have to do it explicitly, telling the interpreter that wherever you use that variable in this scope, it should go straight to global scope and you know what you're doing. On Python 3 you can also assign to the nearest enclosing scope with 'nonlocal'.
Remember that when you assign to a name in Python, this new assignment has nothing to do with that name previously existing assigned to something else. Imagine if there was no default to local and Python searched up all scopes trying to find a variable with that name and assigning to it as it does when reading. Your functions' behavior could change based not only on your parameters, but on the enclosing scope. Life would be miserable.
You say it yourself that with reads there is no ambiguity and with writes there is. Therefore you need some mechanism for resolving the ambiguity with writes.
One option (possibly actually used by much older versions of Python, IIRC) is to just say writes always go to the local scope. Then there's no need for a global keyword, and no ambiguity. But then you can't write to global variables at all (without using things like globals() to get at them in a round-about way), so that wouldn't be great.
Another option, used by languages that statically declare variables, is to communicate to the language implementation up-front for every scope which names are local (the ones you declare in that scope) and which names are global (names declared at the module scope). But Python doesn't have declared variables, so this solution doesn't work.
Another option would be to have x = 3 assign to a local variable only if there isn't already a name in some outer scope with name x. Seems like it would intuitively do the right thing? It would lead to some seriously nasty corner cases though. Currently, where x = 3 will write to is statically determined by the parser; either there's no global x in the same scope and it's a local write, or there is a global x and it's a global write. But if what it will do depends on the global module scope, you have to wait until runtime to determine where the write goes which means it can change between invocations of a function. Think about that. Every time you create a global in a module, you would alter the behaviour of all functions in the module that happened to be using that name as a local variable name. Do some module scope computation that uses tmp as a temporary variable and say goodbye to using tmp in all functions in the module. And I shudder to think of the obscure bugs involving assigning an attribute on a module you've imported and then calling a function from that module. Yuck.
And another option is to communicate to the language implementation on each assignment whether it should be local or global. This is what Python has gone with. Given that there's a sensible default that covers almost all cases (write to a local variable), we have local assignment as the default and explicitly mark out global assignments with global.
There is an ambiguity with assignments that needs some mechanism to resolve it. global is one such mechanism. It's not the only possible one, but in the context of Python, it seems that all the alternative mechanisms are horrible. I don't know what sort of "better reason" you're looking for.
I have a global variable I called Y_VAL which is initialized to a value of 2.
I then have a function, called f() (for brevity), which uses Y_VAL.
def f():
y = Y_VAL
Y_VAL += 2
However, when trying to run my code, python gives the error message:
UnboundLocalError: local variable 'Y_VAL' referenced before assignment
If I remove the last line Y_VAL += 2 it works fine.
Why does python think that Y_VAL is a local variable?
You're missing the line global Y_VAL inside the function.
When Y_VAL occurs on the right-hand-side of an assignment, it's no problem because the local scope is searched first, then the global scope is searched. However, on the left-hand-side, you can only assign to a global that way when you've explicitly declared global Y_VAL.
From the docs:
It would be impossible to assign to a global variable without global, although free variables may refer to globals without being declared global.
This is just how Python works: Assignment always binds the left-hand side name in the closest surrounding name space. Inside of a function the closest namespace is the local namespace of the function.
In order to assign to a global variable, you have to declare it global. But avoid global by all means. Global variables are almost always bad design, and thus the use of the global keyword is a strong hint, that you are making design mistakes.
I ran to the same issue as you and as many others like you, before realising it needs the global statement. I then decided to move everything to object orientation and have piece of mind. Call me insane but I just dont trust myself with the global statement and its not difficult to come against a problem of local scope that is a pain to debug.
So I would advice collect all your "global" variables put them in a class inside an init(self) and not only you wont have to worry about local scope but you will have your code much better organised. Its not a freak of luck that most programmer out there prefer OOP.