Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python global variable doesn't work in function when it is evaluated by an if statement in function

Example 1:

a=1
def b():
    print a
    a=2
    print a

Example 2:

a=1
def b():
    print a
    if a==1:
        a=2
    print a

Example 1 works as expected, Example 2 fails with UnboundLocalError: local variable 'a' referenced before assignment on the first print a

Can someone explain why this happens ? Is it an error or a feature ?

The second example is not very useful but I don't see why it shouldn't work. I would expect function b to first print the global a then check if global a is 1. If that's true local a would be set to 2. Then either global a would be printed or local a depending on the value of global a. Well in the example global a is 1, so I would expect to see local a printed with the value of 2.

Example 3:

a=1
def b():
    print a

works

Example 4:

a=1
def b():
    print a
    a=2

fails, as does Example 1 as correctly commented, I had actually only tested Example 3 and thought it was the same as Example 1.

Now I understand the ever so often repeated thing about the whole scope. It's completely new to me and I have fun with the following example (Ipython):

In [13]: a=1

In [14]: def b():
   ....:     a=2
   ....:     global a
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
   ....:     print a
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
   ....:     
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<input>:3: SyntaxWarning: name 'a' is assigned to before global declaration
<ipython-input-14-4fe1c6cdc9d0>:3: SyntaxWarning: name 'a' is assigned to before global     
declaration
  global a

In [15]: b()
2

In [16]: print a
2

So the mechanism differs from declaring a function or things like that where I can only access the state after I have changed it.

Are there any other actions in python that work like this - travelling through time ?

To make the examples work globals() could be used:

Example 1 working:

a=1
def b():
    print globals()["a"]
    a=2
    print a

Example 2 working:

a=1
def b():
    global_a=globals()["a"]
    print global_a
    if global_a==1:
        a=2
    print a

Example 4 working:

a=1
def b():
    print globals()["a"]
    a=2
like image 203
c.holtermann Avatar asked Feb 28 '26 19:02

c.holtermann


1 Answers

Python determines the scope of a name on the basis of assignment at parse time. If you assign to a name, it is local for the entire scope. You are assigning to a in b() so it is a local name, it is never seen as a global name.

You'll have to tell the parser to treat a as a global explicitly in such a case:

def b():
    global a
    print a
    if a==1:
        a=2
    print a

Note that your first example fails with the exact same error; you are assigning in that version too, so it too raises UnboundLocalError:\

>>> a=1
>>> def b():
...     print a
...     a=2
...     print a
... 
>>> b()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in b
UnboundLocalError: local variable 'a' referenced before assignment
like image 170
Martijn Pieters Avatar answered Mar 02 '26 10:03

Martijn Pieters



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!