python variable scope in function [duplicate] - python

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 8 years ago.
I have found a similar question Python variable scope error. It's related to immutable variable. But when I test mutable variable, I don't know how Python interpreter decides the scope of the variable.
Here's my sample code:
def test_immutable():
a = 1
b = 2
def _test():
print(a)
print(b)
a += 1
print(a)
_test()
def test_mutable():
_dict = {}
def _test():
print(_test.__dict__)
_dict['name'] = 'flyer'
print('in _test: {0}'.format(_dict['name']))
_test()
print(_dict['name'])
if __name__ == '__main__':
# test_immutable() # throw exception
test_mutable() # it's ok

Immutable vs mutable has nothing to do with variable scoping. Variables are just names, and always work the same way. Scoping is even decided at compile time, long before Python knows what you're going to assign to them.
The difference between your two functions is that the first one assigns directly to a with the += operator, which causes a to become a local. The second one assigns to a key inside _dict, which ultimately calls a method on the dict object, and doesn't affect the variable's scoping.

Related

Change a variable inside a function with Python [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 12 days ago.
Im playing around with functions and I never was able to understand why I couldn't change a variable. It always gives me an error.
Iv'e tried googling it but nothing really worked. Could someone help me out with this?
x = 1
def run():
print(x)
x += 1
run()
Since you are assigning to x, you need to declare it as global.
def run():
global x
print(x)
x += 1
Otherwise, the assignment makes it a local variable, one you try to print before assigning to it (and one that isn't initialized before you try to increment it).

Why it's impossible to reassign global name within local scope (without `global` keyword) with using the global name's value in reassignment? [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.
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.

What is so special about += operator? [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 last year.
I wrote a code similar to the following and it gives me the local variable 'a' referenced before assignment error. When I changed that a += [2] into a.append(2), it worked.
def f():
a = [1]
def f1():
a += [2] # => no error with a.append(2)
f1()
print(a)
Why? Why the parser can't recognize the outside a with +=?
It's an assignment to a. It's basically syntactic sugar for
a = a.__iadd__([2])
The assignment makes a a local variable when the code is generated, but then the RHS of the assignment tries to access that variable before at runtime it is defined.
a.append(2), on the other hand, is not an assignment. a is a free variable whose value is taken from the closest enclosing scope.
If you want to assign to a non-local variable, you need to declare the name as non-local first.
def f():
a = [1]
def f1():
nonlocal a
a += [2]
f1()
print(a)

Python inner function sets vs nonlocal [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 1 year ago.
I believe I know the answer to this, but wanted to double-check because I find this a bit confusing.
def outerFunc():
mySet = set()
a = 0
def innerFunc():
mySet.add(1)
mySet.add(2)
a = 7
innerFunc()
print(mySet) # {1, 2}
print(a) # 0
Here, if I want to change the value of a, I need to use nonlocal. The fact that the set changes is just because sets are passed by reference? So, in an inner function we have access to the values of the outer function's variables, but cannot modify them unless they're references?
You can check the python document
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.
So if you assigned a variable and the variable without global just affects the local.
For example, if you assigned value to mySet, then it also does not change.
def outerFunc():
mySet = set()
def innerFunc():
mySet = {1}
mySet.add(2)
innerFunc()
print(mySet) # ''

Unexpected behavior of Python's variable scope [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 7 years ago.
I'm a bit confused as to how Python's variable scope system works. Say I have situation like this:
a = 10
def test():
print(a)
Then everything works just as I expect. Python first looks for a local variable a, fails to find it and then searches for a global variable.
However, in a situation like this:
a = 10
def test():
print(a)
a += 1
print(a)
Python throws an UnboundLocalError exception, apparently originating from line 3 (print(a)). To me it seems that at least to this line nothing has changed, and I don't understand why there is an exception anyway.
Since python does not have variable declarations, every variable assignment inside the scope of a function is considered local. So, you always have to specify that that variable is a global one:
a = 10
def test():
global a
print(a)
a += 1
print(a)
test()

Categories

Resources