views:

88

answers:

3

I have a question about global variable in Python. The code is following. If I do not use global M in function test, It would issue error. But Why it does not show error for string s. I do not declare it as global.

global M
M = []
s = "abc"

def test():
    ### global M
    print M 
    M.append(s)

print M UnboundLocalError: local variable 'M' referenced before assignment

+2  A: 

I'm not quite sure what error you would be getting, but you seem to be using global wrong.

The global keyword is not required (or recommended) for declaring globals. It is instead used inside a function to specify that a local variable should not be created. Consider the 2 different functions:

M = []

def test1():
    M = [1]

def test2():
    global M
    M = [2]

test1 will create a new local variable, while test2 will write to the global M

cobbal
+5  A: 

If I do not use global M in function test, It would issue error.

This statement of yours is simply not true!!!

>>> M = []
>>> s = "abc"
>>> 
>>> def test():
...     M.append(s)
... 
>>> M
[]
>>> test()
>>> M
['abc']

I think you're confusing two utterly and completely different concepts:

  1. binding a barename -- usually by assignment (i.e. =), but also possibly by a few other statements (def, &c)

  2. calling a method (such as append) which "may" happen to mutate the object (only if that object is mutable and the method is a mutator of course, but that does apply when the object is a list and the method is append)

I'm not sure why people can confuse the two poles-apart concepts, but, they surely can. Maybe it's the fact that some non-plain-vanilla "kinds" of assignment are actually calling a (special) method "behind the curtains", e.g., assignment to qualified names (a.b=c is actually calling type(a).__setitem__(a, b), so, calling a method, not rebinding any barename) and augmented assignment (a+=b is actually doing a = type(a).__iadd__(a, b), so, both calling a method and rebinding a barename).

You need global (alas) if and only if you're doing "1": rebinding a barename (including rebinding it by augmented assignment but not including any other special case). Eschew global unless it's really indispensable (and many would say it's never truly indispensable... just "apparently kind of handy" in some cases;-).

Alex Martelli
My error occur when I put "print M" before "M.append(s)".
chnet
@chnet Please copy the error message into your question instead of just talking about it. You are forcing people to read your mind, which does not work as well.
jleedev
@chnet, adding a `print M` statement in function `test` in the snippet I'm giving in my answer works just fine, so, _again_, your statement is just false. Your code must have significant differences from the above, and it's impossible for us to guess what differences there might be since you keep hiding your code from us and making false statements instead of **showing us the code**!-)
Alex Martelli
A: 

As @Alex Martelli pointed out your code as shown doesn't produce an error, but putting that aside for now to build on @cobbal's answer (sorry I cannot comment yet) you need to be really careful when it comes to the scope here

In @cobbal's answer:

def test1():
    M = [1]

creates a new variable M local to the function test1. However, if instead of doing an assignment M = [1] he had used M.append(1), as was done in the question, instead of creating a new local variable Python would look up from the local scope of the function into the higher scopes, in this case the global scope where there is indeed already a variable M which points to an empty list. In this case Python will find this variable and simply append to the existing list resulting in global M now pointing to [1].

In the second example:

def test2():
    global M
    M = [2]

The use of the global keyword is essential to avoid the local assignment which would otherwise occur. By invoking global use of M in the local scope of the function will point to the already existing [] object outside of the function.

You can prove this to yourself by inserting id(M) into the various forms of the function to show which implementations cause the M inside the function to point to a global or local object.

dtlussier