This is a weird behavior.
Try this :
rep_i=0
print \"rep_i is\" , rep_i
def test():
global rep_i #without Global this gives error but list , dict ,
If you had assigned a new value to rep_lst
inside of test2
(not just to one of its elements, as you did) it would not work without the global
flag. In Python, if you do not assign to a variable inside a function it will look for that variable in in more global scopes until it finds it.
For example, in this code segment I define the list both globally and inside of example()
. Since the variable in example()
is closer in scope to example2()
than the global one is, it is what will be used.
x = ["out"]
def example():
x = ["in"]
def example2():
print x # will print ["in"]
This has nothing to do with lists, but is the behaviour of any variable in Python.
Here's an example that demonstrates that a non list
/dict
variable is available in a subroutine, and the problem is, as everyone says, the act of rebinding
in your original code sample:
x = 1
def test():
y = x + 1
print y
test()
You'll see this prints out 2
, despite x
not being declared global.
You only need to use global
if you are assigning to the global name. Without global
, an assignment creates a new local.
There's nothing special about how global
applies to a list—global
simply influences scope and name resolution.
There is an error in python called UnboundLocalError
which often confuses newcomers. The confusing thing is: future assignment does change the way a variable is looked up.
When the interpreter sees a variable name for the first time, it looks ahead to the end of current code block, and if you don't have an assignment to it anywhere within the same block of code, the interpreter considers it global. If you do, however, then it is considered local, and any reference to it before assignment generates an UnboundLocalError
. That's the error you got. That's why you need to declare global rep_i
. If you did not assign rep_i
, you wouldn't need this line.
Also, this has nothing to do with variable type. Also, assigning or appending an item to the list (which you probably meant to do, but did not) is not assignment of the list itself, it is essentially calling a method on a list object, which is different from assignment: assignment creates a new object (possibly under a name that already exists), while manipulating a list just changes an existing list. You can try:
In [1]: # It won't work with small integers, as they are cached singletons in CPython
In [2]: a = 123123
In [3]: id (a)
Out[3]: 9116848
In [4]: a = 123123
In [5]: id(a)
Out[5]: 9116740
In [6]: # See, it changed
In [7]: # Now with lists
In [8]: l = [1,2,3]
In [9]: id(l)
Out[9]: 19885792
In [10]: l[1] = 2
In [11]: id(l)
Out[11]: 19885792
In [12]: # See, it is the same
In [13]: # But if i reassign the list, even to the same value
In [14]: l = [2,2,3]
In [15]: id(l)
Out[15]: 19884272
It isn't automatically global.
However, there's a difference between rep_i=1
and rep_lst[0]=1
- the former rebinds the name rep_i
, so global
is needed to prevent creation of a local slot of the same name. In the latter case, you're just modifying an existing, global object, which is found by regular name lookup (changing a list entry is like calling a member function on the list, it's not a name rebinding).
To test it out, try assigning rep_lst=[]
in test2
(i.e. set it to a fresh list). Unless you declare rep_lst
global
, the effects won't be visible outside test2
because a local slot of the same name is created and shadows the global slot.