views:

59

answers:

4

Please see the following code:

def good():
  foo[0] = 9         # why this foo isn't local variable who hides the global one

def bad():
  foo    = [9, 2, 3] # foo is local, who hides the global one

for func in [good, bad]:
  foo = [1,2,3]

  print('Before "{}": {}'.format(func.__name__, foo))
  func()
  print('After  "{}": {}'.format(func.__name__, foo))

The result is as below:

# python3 foo.py
Before "good": [1, 2, 3]
After  "good": [9, 2, 3]
Before "bad" : [1, 2, 3]
After  "bad" : [1, 2, 3]
+6  A: 

Because you're not setting foo, you're getting something in foo (foo[0] to be exact).

In bad you create a new variable foo. In good you do something like foo.set(0, 9) (set item 0 to value 9). Which is using a variable, and not defining a new name.

extraneon
I guess you are right. No settings, no new name.
aXqd
A: 

Variables will look to their inner scope first then to outer scopes in python. For instance:

FOO = 'global'

def printfoo():
    print FOO
# prints 'global'

def printfoolocal():
    FOO = 'local'
    print FOO
# prints 'local'

If you'd like to modify a globally scoped variable, you need to use the global keyword

def modifyfoo():
    global FOO
    FOO = 'modified'
print FOO
# prints 'modified'
xyld
I know this behavior, just curious about the differences in both cases. I think @extraneon answered my question. Thanks, anyway.
aXqd
A: 

To make simple, python first look in the local variables and after in the global ones. (For reading or for creating a variable)

So, in good, you take the foo variable : No local foo variable and a global foo variable => you take the global one and you modify it.

In bad, you create a new (local) variable, so the global one is not modified.

You can specify that a variable is global with the global keyword :

def good2():
    global foo
    foo    = [9, 2, 3]
Matthieu Gautier
> "So, in good, you take the foo variable : No local foo variable and a global foo variable => you take the global one and you modify it."My question is exactly why wouldn't this behavior happen in 'bad'. What are the rules here?
aXqd
A: 

If, like good, you want to replace the contents of the list foo, then you could assign to a slice of the whole list like:

def good2():
    foo[:] = [9, 2, 3]

Just like where good assigned to one element of the list, this replaces the whole contents.

In bad you were binding a new list to the name foo.

neil
yep, 'good2' should be the same as 'good'
aXqd