开发者

Why changing global does not give error?

Why on earth Python lets change not global declared list in function?

RE-UPDATED

numbers = []
num = 4

def add(n, thisnum=None):
    # changing global list without global declaration!
    numbers.append(n)
    if thisnum:
         num = thisnum
         print 'num assigned', thisnum
    ##numbers = ('one', 'two', 'three')
    ## adding this line makes error:
"""Traceback (most 开发者_如何学Gorecent call last):
  File "J:\test\glob_vals.py", line 13, in <module>
    add(i)
  File "J:\test\glob_vals.py", line 6, in add
    numbers.append(n)
UnboundLocalError: local variable 'numbers' referenced before assignment
"""

for i in (1,2,3,564,234,23):
    add(i)

print numbers
add(10, thisnum= 19)
# no error
print num
# let the fun begin
num = [4]
add(10, num)
print num

# prints:
"""[1, 2, 3, 56, 234, 23]
num assigned 19
4
num assigned [4]
[4]

"""

If I put assignement to variable with same name then the action before that line becomes error, not the added line (byte code compiler spots it, I guess).


You aren't assigning to the global variable, you are calling a method on it which changes its contents. This is allowed.

What you can't do without the global keyword is this:

def add(n):
    #global numbers
    numbers = numbers + [n]

Result:

Traceback (most recent call last):
  File "C:\Users\Mark\Desktop\stackoverflow\python\test.py", line 8, in 
    add(i)
  File "C:\Users\Mark\Desktop\stackoverflow\python\test.py", line 5, in add
    numbers = numbers + [n]
UnboundLocalError: local variable 'numbers' referenced before assignment

The difference is that here I am not mutating the existing list - I'm trying to create a new list and reassign back to the global scope. But this cannot be done without the global keyword.


Regarding your update:

The following line is OK because it creates a new local name num in the scope of the function. This does not affect the value of the variable at the global scope.

num = thisnum


global x only affests x = ... (namely, it makes this re-assign the global x instead of creating an independent local x). It doesn't affect x.member = ... (because that's a method call) or x.mutating_method(...), because Python (this is not an issue of static vs. dynamic, btw) can't know (and doesn't care) that these method modify self in some way - so you'd have to prevent method calls on (objects pointed to by) global variables ... which is, of course, pointless.

Regarding update: When you do num = thisnum, you are doing something completely different from numbers.append(n) - you are creating a local variable (because you didn't declare global num) and assigning it some value. This never even touches the global num.


Because you are just appending to a list.

Accessing and assigning are different concepts. When you append a list, you are just calling a method which changes its value. Supposing you did +=, that would be assigning.

If you were to do this:

>>> numbers = []
>>> def add(n):
      numbers += n

>>> n = [1, 2]
>>> add(n)

It would fail because this is assignment.

To fix this, in the add() function, you add:

>>> def add(n):
        global numbers
        numbers += n
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜