This question already has answers here:
Short description of the scoping rules?
(9 answers)
Closed 5 years ago.
I was thinking that variable can be only accessed after its declaration.
But apparently, Python's name resolution starts to look for from inside to outer.
My question is that this is bad practice in terms of readability? I was wondering that this might be a common knowledge for Pythonista so that I can write this kind of code from now on.
def outer():
def inner():
print x
x = ‘foo’
inner()
>>> outer()
>>> ‘foo’
When you invoke inner(), it starts executing. On line print x it sees variable name x. Then it looks to inner scope of function inner, doesn't find variable x there. Then it looks to the outer scope, namely, scope of outer. At this moment there is already variable x defined (as it is done before inner() invokation) and this variable is used.
Related
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.
If we run this code
a = 1
def foo():
b = a + 2
print(b)
foo()
it works.
But if we run this code
a = 1
def foo():
b = a + 2
print(b)
a = a + 4
print(a)
foo()
it doesn't work.
Question:
why in the first example b = a + 2 works without errors but in the second example the same line of code b = a + 2 is broken?
why if there is no reassignment of a we can get a from a global scope but if there is a reassignment we don't have an access to a even if new local a doesn't even exist yet (because the reassignment isn't finished).
Question: Why [...] the first example works without errors but in the second example the same line of code is broken?
Because in the first example, you're only reading from a global a, then writing to a local b.
In the second example, a is assumed to be a local too (since you're not declaring global a), and it has no value when you're trying to read it in the first line, hence an error.
This is similar to JavaScript's Temporal Dead Zone, if that's familiar.
As for the question in your title:
Why it's impossible to reassign global name within local scope (without global keyword) with using the global name's value in reassignment?
You're not reassigning
a global name at all in either of your examples, since indeed you're not using the global keyword. In Python, you can always read a global (or "ambient") name; otherwise it'd be a pain to e.g. use any builtin function (since they're not locals), and having a special exception for builtins would be, well, a special exception, and those aren't nice.
This question already has answers here:
How do global and local variables behave in this case? [duplicate]
(3 answers)
Closed 5 years ago.
I have written a simple function to understand local and global scope in Python .
x = 50
def func(x):
print('x is', x)
x = 2
print('Changed local x to', x)
func(x)
print('x is still', x)
what I want to understand here is inside the function during x= 2 assignment whether any new variable is getting created as the globally the variable x is still holding the value 50 . How this process occurs in Python?
Yes, a new variable is created. Python's scoping rules mean that variables of the same name in different scopes are unrelated - variable references are always to the innermost scope containing a variable with that name unless this is overridden with a global statement.
This question already has answers here:
Assigning to variable from parent function: "Local variable referenced before assignment" [duplicate]
(5 answers)
Short description of the scoping rules?
(9 answers)
Closed 8 years ago.
I come from a land of heavy Java and PHP experience so when it comes to Python much of the rules do not make sense to me.
I have a recursive Fibonacci function below that spits out the error:
Traceback (most recent call last):
File "C:\Users\Nic\workspace\lab8\src\Main.py", line 26, in <module>
print fibcount(27),"took",calls,"calls."
File "C:\Users\Nic\workspace\lab8\src\Main.py", line 19, in fibcount
calls += 1
UnboundLocalError: local variable 'calls' referenced before assignment
Here is my code:
calls = 0
def fibcount(n):
calls += 1
if n < 2:
return (1,1)
f1,c1 = fibcount(n-1)
f2,c2 = fibcount(n-2)
return (f1+f2,c1+c2+1)
print fibcount(27),"took",calls,"calls."
In Java this would obviously work because calls is a global variable in respect to the function fibcount() so it confuses me that calls is somehow not in scope.
What am I doing wrong?
In Python, you need to declare global variables as being global inside functions which reassign them to a different value. You would use global for this:
def fibcount(n):
global calls
...
Otherwise, Python will treat the calls variable as if it were local.
Note however that you only need to do this for global variables which you reassign. Simply reading their values will work fine.
Also, reassigning global variables like this is considered ugly in Python and should be avoided whenever possible. Most of the time, you should stick to passing values to functions and then reassigning variables to their return values. If you need to maintain state, use a class.
The only time global variables are warranted in Python is when you want to have module-level constants. And in that case, the convention is that they should have all-caps names:
MYCONST = 12345
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)
Why does code like `str = str(...)` cause a TypeError, but only the second time?
(20 answers)
Closed 6 months ago.
Could anyone explain the exception the below code. It only works when I change the var sub in the display() to another name. There is no global variable sub as well. So what happened ?
def sub(a, b):
return a - b
def display():
sub = sub(2,1) // if change to sub1 or sth different to sub, it works
print sub
Any variable you assign to inside a scope is treated as a local variable (unless you declare it global, or, in python3, nonlocal), which means it is not looked up in the surrounding scopes.
A simplified example with the same error:
def a(): pass
def b(): a = a()
Now, consider the different scopes involved here:
The global namespace contains a and b.
The function a contains no local variables.
The function b contains an assignment to a - this means it is interpreted as a local variable and shadows the function a from the outer scope (in this case, the global scope). As a has not been defined inside of b before the call, it is an unbound local variable, hence the UnboundLocalError. This is exactly the same as if you had written this:
def b(): x = x()
The solution to this is simple: choose a different name for the result of the sub call.
It is important to note that the order of use and assignment makes no difference - the error would have still happened if you wrote the function like this:
def display():
value = sub(2,1) #UnboundLocalError here...
print value
sub = "someOtherValue" #because you assign a variable named `sub` here
This is because the list of local variables is generated when the python interpreter creates the function object.
This was originally a comment. The OP found this useful as an answer. Therefore, I am re-posting it as an answer
Initially, sub is a function. Then, it becomes the return value of a function. So when you say print sub, python doesn't know which sub you are referring to.
Edit:
First you define a function sub. Now, python knows what sub is.
When you create a variable and try to assign to it (say x = 2), python evaluates the stuff on the right hand side of the = and assigns the value of the evaluation as the value of the stuff on the left hand side of the =. Thus, everything on the right hand side should actually compute.
So if your statement was x = x+1, then x better have a value assigned to it before that line; and the previously defined x has to be of some type compatible with the addition of 1.
But suppose x is a function, and you make a variable called x in some other function, and try to assign to it, a value computed with function x, then this really starts to confuse python about which x you are referring to. This is really an oversimplification of this answer, which does a much better job of explaining variable scope and shadowing in python functions
For every variable used, Python determines whether it is a local or a nonlocal variable. Referencing a unknown variable marks it as nonlocal. Reusing the same name as a local variable later is considered a programmers mistake.
Consider this example:
def err():
print x # this line references x
x = 3 # this line creates a local variable x
err()
This gives you
Traceback (most recent call last):
File "asd.py", line 5, in <module>
err()
File "asd.py", line 2, in err
print x # this line references x
UnboundLocalError: local variable 'x' referenced before assignment
What happens is basically that Python keeps track of all references to names in code. When it reads the line print x Python knows that x is a variable from a outer scope (upvalue or global). However, in x = 3 the x is used as a local variable. As this is a inconsistency in the code, Python raises an UnboundLocalError to get the Programmers attention.
Python start executing your code and get the function first
def sub(a, b):
return a - b
So after executing this interpreter get the sub as a function. Now when come to next line it found
def display():
sub = sub(2,1) // if change to sub1 or sth different to sub, it works
print sub
so first line sub = sub (2, 1) will convert the sub function to sub variable. From this function you are returning the sub variable. So its create problem.
This question already has answers here:
What's the scope of a variable initialized in an if statement?
(7 answers)
Closed 3 years ago.
In Python, are variable scopes inside if-statements visible outside of the if-statement? (coming from a Java background, so find this a bit odd)
In the following case, name is first defined inside the if-block but the variable is visible outside of the if-block as well. I was expecting an error to occur but 'joe' gets printed.
if 1==1:
name = 'joe'
print(name)
if statements don't define a scope in Python.
Neither do loops, with statements, try / except, etc.
Only modules, functions and classes define scopes.
See Python Scopes and Namespaces in the Python Tutorial.
Yes, in Python, variable scopes inside if-statements are visible outside of the if-statement.
Two related questions gave an interestion discussion:
Short Description of the Scoping Rules?
and
Python variable scope error
All python variables used in a function live in the function level scope. (ignoring global and closure variables)
It is useful in case like this:
if foo.contains('bar'):
value = 2 + foo.count('b')
else:
value = 0
That way I don't have to declare the variable before the if statement.