-1
myList = [5, 2]
def foo():
    myList[0] = 6

In the example above, myList is still mutated, though it is non-global and not passed in by parameter. This doesn't work however, if the variable is not a list.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Manh Nguyen Huu
  • 331
  • 1
  • 4
  • 12
  • I thought that if you want to mutate something in a function you have to call: global myList? – Manh Nguyen Huu Jan 08 '17 at 18:20
  • only when you reassign new value to given name. You are not in this case. – Łukasz Rogalski Jan 08 '17 at 18:22
  • Not when mutating elements of a list `list[0] = 4` will work while `list = [4, 5]` will not. – Nick is tired Jan 08 '17 at 18:22
  • http://stackoverflow.com/questions/10262920/understanding-pythons-call-by-object-style-of-passing-function-arguments – Łukasz Rogalski Jan 08 '17 at 18:23
  • This question isn't a duplicate of the linked question, because the other question is about argument passing in Python and here no arguments are passed. – mkrieger1 Jan 08 '17 at 18:35
  • Also see http://nedbatchelder.com/text/names.html – PM 2Ring Jan 08 '17 at 18:35
  • @mkrieger1 I agree the questions are different, but the answers of the linked question explain the core concept of Python's names & objects that also apply here. – PM 2Ring Jan 08 '17 at 18:43
  • Here is a more appropriate duplicate of this question: http://stackoverflow.com/questions/575196 – FMc Jan 08 '17 at 18:51
  • Maybe this one is a better dupe target: [Why is the global keyword not required in this case?](http://stackoverflow.com/questions/14081308/why-is-the-global-keyword-not-required-in-this-case) The OP's code in that question uses a dict instead of a list, but the principle's the same. – PM 2Ring Jan 09 '17 at 07:22

2 Answers2

2

The scope rules are roughly like this:

  • Local scope: you define the variable inside a function
  • Enclosing scope: your function is inside another function (or multiple layers of functions), and one of the higher (enclosing) functions declared the variable
  • Global scope: the global scope (module or file)
  • Built-in: Any built-in values native to Python

This is known as the LEGB rule.

In your case, it is because you are not assigning a value to the name myList inside of foo(). You are only assigning a value to the 0 index of an existing list. Therefore the global value of myList is the scope you are using.

Dan Lowe
  • 51,713
  • 20
  • 123
  • 112
2

myList is a global variable, though. It exists in the context of foo, where you access and modify one of its elements.

myList = [0, 5]

def foo():
    myList[0] = 6

print('Before foo: {}'.format(myList))
foo()
print('After foo: {}'.format(myList))

Output

Before foo: [0, 5]
After foo: [6, 5]

This doesn't work however, if the variable is not a list.

I assume that you tried something similar to the following:

a = 0

def bar():
    a = 6

print('Before bar: {}'.format(a))
bar()
print('After bar: {}'.format(a))

Output

Before bar: 0
After bar: 0

In this case, you don't observe any change in the global variable a because within bar you're assigning to a new local variable a which shadows the global variable of the same name. You set the local variable a to 6, which has no effect as the variable is discarded as soon as the function ends.

You can show that even simple integers declared in the global scope can be accessed within function scopes by running something like the following. In this case, we specify that the function should modify an existing global variable b rather than assigning to a new local one.

b = 0

def baz():
    global b
    b = 6

print('Before baz: {}'.format(b))
baz()
print('After baz: {}'.format(b))

Output

Before baz: 0
After baz: 6
Tagc
  • 8,736
  • 7
  • 61
  • 114
  • Example of `global` keyword might be helpful here since it shows how one _can_ assign to a global variable from the local scope. Python just assumes you don't normally mean that (and has no syntax for explicitly declaring a variable) – pvg Jan 08 '17 at 18:24
  • @pvg Step ahead of you. :) – Tagc Jan 08 '17 at 18:24