UnboundLocalError: local variable 'url_request' referenced before assignment [duplicate] - python

This question already has answers here:
Using global variables in a function
(25 answers)
Closed 8 years ago.
Think I'm going nuts here.
url_request = 0
def somefunction():
url_request+=1
if __name__ =='__main__':
somefunction()
Gives me the UnboundLocalError. What important concept am I missing here?

You are assigning to a global variable, which means you need to mark it as a global:
def somefunction():
global url_request
url_request+=1
When you assign to a variable in a local scope, it is assumed to be a local variable unless you use a global statement to tell python otherwise first.

For Python 2.7 we have to types of variables: global, local. Each function create it's own local scope for variables.
From local scope you can read without any restrictions. You can also call global object methods, so you can modify variable from global. But you can't reassign value.
Look at this code:
requests = [1,2,3]
def modify():
requests.append(4)
def redeclare():
requests = [10,20,30]
modify()
print requests
# will give you [1,2,3,4]
redeclare()
print requests
# will give you [1,2,3,4]
What's going on? You can't reassign requests variable from local scope, so interpreter create for you other variable - in local scope for redeclare call context.
Regarding to your code... Firstly, you try to reassign variable from global scope. Why? url_request is int, int is immutable, so operation url_request+=1 doesn't change value, it should reassign new value to variable name. Secondly, you don't specify global identify for this variable. So only one option for interpreter - to assume url_request as local variable. But... You didn't declare it's value anywhere....
UnboundLocalError means that you try to perform operations with variable value without declaring it before. Hope this will help you to understand more about Python variables/names/scopes.

Related

Global and local scope in python

Just a beginner question about local and global scope in python
X = 100
#is X a global variable?.We defined it outside the function scope
def foo():
print(X)
return X
#it prints 100 and even returns it
def foo():
X = X + 10
#local error
#UnboundLocalError: local variable 'X' referenced before assignment
def foo():
global X
# if X is a global variable why specify again?
X = X + 10
return X
To modify global copy of a variable you need the to use the global keyword, but you don't need global if you are only accessing that.
from the python website:
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global.
this means that you can access a global variable inside a function without a global keyword. if you want to change it though, you must use the global keyword beforehand.
global and nonlocal are very strange things when I was a beginner.
Just think about it: why do we need them in Python?
It is because we don't need var, let and such similar things to declare variables.
Think about Javascript, it is dynamic script language too and very alike to python, but it needs var or let or const to declare variables.
The most important thing of declaring variables is to determine scope.
So, in Python, our variables have implicit default scope: current scope where they are defined, and if we want to change scope of some variables, we need use global or nonlocal explicitly .
All names on the left side of = mean to define variables.
Before executing code of some certain scope, Python will pre-compute all local variables, which are those on the left side of =. This is why you got UnboundLocalError: local variable 'X' referenced before assignment in:
def foo():
X = X + 10
So, if we look up those names not in defined current scope, just
follow the rules of scope chain: up, up, up and until built_in.
Remember: scope of any name on the left side of = is default current scope, and you have to assign it(bind something to it) before referring it.

Why does python behave this way with variables? [duplicate]

This question already has answers here:
UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)
(14 answers)
Closed 5 months ago.
I have been trying to understand why python behaves this way, in the block of code below. I have done my research but couldn't find a good answer so I came here to see if anyone can point me in the right direction or provide a good clarification.
I understand that it has to do with some old ALGOL principle, but I don't fully understand it.
var = 5
def func1():
print(var)
func1()
def func2():
var = 8
print(var)
func2()
def func3():
print(var)
var = 8
func3()
The output of this code is as follows:
5
8
UnboundLocalError: local variable 'var' referenced before assignment
I understand why we get the outputs '5' and '8'. But with 'func3()', I was expecting an output of '5'. As it seems, the interpreter thinks that I want to print the local 'var' in the function instead of the global 'var'. So it throws this error.
Or maybe if a variable is defined somewhere inside of the function, then the function will default to the local variable, instead of a global one with the same name.
But why exactly does python behave this way ? I am not complaining, I am just trying to understand something...
How could I use a predefined global variable in a function, then define a local variable with the same name inside of the same function, without changing the value of the global variable ? ( in python of course )
Thanks in advance to everyone here. You are amazing people ! :)
Edit_1: Thanks every one for the great answers. I totally understand that it is a bad and unpractical idea to use a predefined global variable in a function, then define a local variable with the same name inside of the same function. I was just thinking about it from a theoretical perspective, because I saw it in a college lecture. XD
I can't find a single use case, in which it would be optimal to do that either !
Edit_2: I already read the PEP8 and I know that being explicit is better than being implicit. :)
It's true. Otherwise the code will be confusing and lead to bugs.
That question was just about some useless and impractical college theory that I was trying to understand.
Edit_3:
Now I fully understand why it happens and what is going on here. Thanks to Randall Valenciano for providing this link to a blog that explains it very well.
What happens is that the function is interpreted as a whole, and not line by line. So when the function is being interpreted, the variable declarations of any defined variables, are moved to the top of the function. So when we are printing 'var', the function is using the locally declared variable that doesn't have any value assigned to it yet, and then the interpreter complains about it and throws and error.
Thanks to all of you again ! :)
You have been of great help to me ! Now I finally understand what is going on there under the hood.
Your var is defined as a global variable. In each function when you're only reading the var you're accessing the global var, but the moment there's an assigned value to var somewhere in the function, python treats every var within the function as a local variable. Thus why your last function failed, because print(var) (the local varaible) was called before var = 8 was assigned.
You can read up a bit about more in these threads:
How bad is shadowing names defined in outer scopes?
Python nonlocal statement
The best thing to do is be explicit about your code so it's no longer confusing if you're trying to reference a local, nonlocal or global variable.
In this case, assuming your intention is to keep using the global var, do this:
var = 5
def func1():
print(var)
func1()
def func2():
global var
var = 8
print(var)
func2()
def func3():
global var
print(var)
var = 8 # technically this is not necessary any more var = 8 was already assigned when func2() is called
func3()
The output is thus:
5
8
8
Edit: Thanks to juanpa.arrivillaga's comment - I missed your original question.
How could I use a predefined global variable in a function, then
define a local variable with the same name inside of the same
function, without changing the value of the global variable ? ( in
python of course )
The short answer is - define the local var first like you did in func2() and you're good. The longer answer though is - why would you want to do that? It creates confusion and becomes a headache to track which is when you have variables of the same name in different scope. A better approach would be name your local var to be local_var or something so it's distinctly different and easily traced.
Here's a rule for Python Scope Resolution from this answer
LEGB Rule.
L, Local — Names assigned in any way within a function (def or lambda)), and not declared global in that function.
E, Enclosing-function locals — Name in the local scope of any and all statically enclosing functions (def or lambda), from inner to outer.
G, Global (module) — Names assigned at the top-level of a module file, or by executing a global statement in a def within the file.
B, Built-in (Python) — Names preassigned in the built-in names module : open,range,SyntaxError,...
So basically in your question, the scope resolution is "from inside out" and since you aren't using the global keyword, the interpreter doesn't know to look outside the local function scope to find that variable var. All the interpreter sees is that you are using a variable before declaring and defining it, thus throwing the error. Global variables are often dangerous, and so Python wants to make sure you know you want to use a global variable by forcing you to be explicit about it.
See this other answer for an explanation of the global keyword
Hope it helps.

globals() scope inside a function [duplicate]

This question already has answers here:
Short description of the scoping rules?
(9 answers)
Using global variables in a function
(25 answers)
Closed 5 years ago.
I have a question regarding globals() in python
My sample code
b=9
def a1():
'kkk'
a1()
print globals()
I got output b as global
Since b is global, I am expecting I can modify it anywhere
So I modified my code to
b=9
def a1():
'kkk'
b=100
a1()
print globals()
still my globals() says b as 100. Why b inside the function is taken as local value while my globals() says its global?
Note: If I add keyword global b inside the function, it get convert to global.
My question is why b was not getting modified inside the function while globals() declare b as global ?
Refer Python docs for more information. Copying the text in case URL doesn't work
In Python, variables that are only referenced inside a function are implicitly global. If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global.
Though a bit surprising at first, a moment’s consideration explains this. On one hand, requiring global for assigned variables provides a bar against unintended side-effects. On the other hand, if global was required for all global references, you’d be using global all the time. You’d have to declare as global every reference to a built-in function or to a component of an imported module. This clutter would defeat the usefulness of the global declaration for identifying side-effects.
inside a function, unless you use the keyword global, it is not global variable that is modified. instead,a local variable is created and is destroyed as soon as it is out of scope
As your code b is a local variable in a1(), to use global variable, you should first say that to python and then use it, as follows:
b=9
def a1():
'kkk'
global b
b=100
a1()
print globals()

How to use shadowing with global variables?

I have notes from class but I am unsure what is actually happening.
Other than adding to confusion, what purpose does shadowing allow on to do? I thought the because globalString is a string type it cannot be modified? How do I access the original value? What is an instance of what in memory terms?
globalList = [1,2,3]
globalString = "global" # can't be modified because it's a string
def updateGlobalString():
global globalString # Does line this do anything?
globalString = "new"
print(globalString)
>>> "global"
updateGlobalString()
>>> "new"
def updateGlobalList():
globalList.append(4)
print(globalList)
>>> [1,2,3]
updateGlobalList()
print(globalList)
>>> [1,2,3,4]
If python Lists are mutable how does this example change the equation when compared to strings? And just to clarify, are any of these values actual Global?
Thank you.
Shadowing isn't a technique or a tool, it's something that is simply a consequence of Python's scoping rules.
I'm confused by your question about whether any of the variables are global. Anything declared at module level is global. The global keyword, when used in a non-global scope, allows you to rebind the name to a different object and have that rebinding take effect in the global scope too: otherwise you would simply be defining a new variable in the local scope (which would indeed be shadowing the original variable).
Global means that variable is going to occur in the global space. So that 1st function deletes the old string in global namespace and replaces it with a new one. However, a list is mutable and as a direct result can be changed outside of the global scope.

Confusion about Python variable scope

I came across some code which kind of puzzled me. Here's a minimal example which shows this:
# of course, the ... are not part of the actual code
some_var = {"key1":"value1" ... "keyN":"valueN"}
def some_func():
v = some_var["key1"]
The code works, but the fact that I can access some_var directly confuses me. The last time I had to write some Python code, I remember having to write some_func like this:
def some_func():
global some_var
v = some_var["key1"]
I am using Python 2.7.1 on a Windows 7 PC. Did something change in the 2.7 release that allows for this?
No, you just can't reassign some_var in a local scope. Consider the following:
some_var = {}
def some_func():
# some_var[5] = 6
some_var = {1:2}
some_var[3] = 4
some_func()
print (repr(some_var)) # {}
You'll see the assignment in some_func actually creates a local variable which shadows the global one. Therefore, uncommenting the line would result in an UnboundLocalError - you can't access variables before they're defined.
There's a difference between using (e.g. calling or using in an expression) a name from an outer scope and assigning it (and there's a difference between assigning a bare variable and assigning a member of an object pointed to by a variable - x.y = ... and x[...] = ... count as method calls!).
You only need to declare that a variable is from an outer scope if you're re-assigning it. In Python 2, you can only do that with global variables (via global var), in Python 3 you can do it for abritarily nested scopes (e.g. closures) using nonlocal var.
Using a nonlocal variable as in you example doesn't require global. It does, however, as soon as you assign the variable (with the aforementioned definition of assignment) anywhere within that scope - so add a line some_var = ... after the line where you're using it and you'll get an UnboundLocalError. Refer to the documentation for the nitty gritty details.
You only have to use global if you want to assign a new value to that variable.
Nested scope was introduced in Python 2.1 (and enabled by default in Python 2.2) (emphasis mine):
Put simply, when a given variable name is not assigned a value within a function (by an assignment, or the def, class, or import statements), references to the variable will be looked up in the local namespace of the enclosing scope. A more detailed explanation of the rules, and a dissection of the implementation, can be found in the PEP.
You only need to use global if you intend to assign to the variable, for reading the variable this is not necessary. This difference is not arbitrary, though it may seem like it at first glance.
When reading a value the interpreter can just look for a local variable named some_var, if it cannot find it then it looks for a global variable of that name. These are simple and straight forward semantics.
When assigning values to a variable the interpreter needs to know whether you intend to assign to a local variable some_var or a global variable. The interpreter assumes that some_var = 2 when called within a function is assigning to a local variable, this makes sense since this is the most common case. For the relatively rare times when you want to assign to a global variable from within a function then you use the global modifier global some_var = 2.
It depends on the usage of the variable in the function
Python variable scope error
Assigning a value to a name makes the name local, unless the name is explicitly declared global.
a = 12
def foo():
a = 42
print a # uses local
foo()
>>> 42
def foo():
global a
a = 42
foo()
print a
>>> 42
If a name is not assigned to, it is global.
a = 12
def foo():
print a # uses global
foo()
>>> 12
In short, you only have to explicitly declare a name global if you will be assigning to it. If you are just reading from it, you can use it at will. However, if you ever assign to the variable, it will be considered local in that function unless you declared it global.
b = 5
def foo():
print b
b = 7
foo()
>>> ???
Since b is assigned to in foo() and not declared global, Python decides at compile time that b is a local name. Therefore b is a local name throughout the whole function, including at the print statement before the assignment.
Therefore the print statement gives you an error, because the local name b has not been defined!

Categories

Resources