-7

With the example code below:

mat = []
x = 5
def add(c,b):
        print c+b
        x = 8
        mat.append(c)
        mat.append(b)
add(5,6)
add(8,9)
print mat
print x

mat is getting appended but why isn't x changing? Why is python treating the list and a variable a different way?

Arafangion
  • 11,517
  • 1
  • 40
  • 72
surya
  • 171
  • 2
  • 12
  • 2
    http://stackoverflow.com/questions/146359/python-scope – Arafangion Feb 17 '12 at 06:23
  • How do you expect python to treat them the same if you don't treat them the same yourself? You mutate `mat` but assign something new to (a new) `x`. Try `mat = [8]` inside the function instead of `mat.append` and you see that now the list isn't treated any different. Any mutation will carry on and any asignment won't. – hajef Apr 25 '19 at 15:28

5 Answers5

10

Don't think of variables in Python as named boxes in which you store data. Think of them as nametags you stick on objects.

In your function, you are sticking the name x on the object 8. This is a local name, so it goes away when the function ends. Inside the function, the local name x "shadows" (prevents access to) the global name x so the global name x is not affected by the assignment. It still points to the object 5 and when you print it outside the function, that's what you get.

You are not changing what object the name mat refers to inside the function. Rather you are changing (mutating) the object pointed to. A method call, even one that changes the object, is not the same as an assignment. No local name mat is created so you are mutating the same object you created outside the function.

This is a common pitfall for beginning Python programmers, but it is understood easily enough and once understood, does not pose any significant difficulty in programming in the language.

The fact that you don't understand something doesn't make it "UNFAIR." Python has been around for more than two decades. It was designed by very smart people and is used by, probably, tens of thousands of programmers around the world. If there were something wrong with Python at this fundamental of a level, it would have been fixed by now.

kindall
  • 178,883
  • 35
  • 278
  • 309
  • I agree that python is one of the best languages designed by experts and smart people. And I agree with ur explanation. But my question is how is mat visible inside the nested function? if mat is visible, so should be x? Python should be reasonable right. – surya Feb 17 '12 at 10:24
  • 1
    @surya, x was visible - until you hid it by creating a local variable also called x. Had you done mat=[c,b] you would have seen the same behaviour there. – Dave Feb 17 '12 at 12:39
  • @Dave, x is not visible inside the function add(c,b). without assigning 8, i tried to print it. it resulted in a traceback – surya Feb 21 '12 at 06:11
  • @surya what version of python are you using? Because that is categorically not the behaviour I get with 2.7. It prints x happily. The only way I can get a traceback is if I try to print a new variable, in which case it throws a NameError: global name 'y' is not defined. If there had been a global variable of that name, it would have printed it. – Dave Feb 23 '12 at 15:17
  • There will be an `UnboundLocalError` when you try something like `x += 1`. That is a hickup and arguably a flaw in the language but it can be handled by calling `global x` beforehand. (see [here](https://emptysqua.re/blog/python-increment-is-weird/)) – hajef Apr 25 '19 at 15:39
3

Mutation and rebinding are two different operations. The former modifies the object regardless of where it may be, whereas the latter only modifies the local name, leaving other names untouched.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
2

The add function there does the following:

  1. Print the result of c+b
  2. Create a new variable in the local scope, referring to the value 8.
  3. Locate mat, and invoke the member function append(c)
  4. Locate mat, and invoke the member function append(b)

As a result, mat and x both continue to refer to the same objects they referred to before, however the list represented by mat has changed, because of the add calls.

Arafangion
  • 11,517
  • 1
  • 40
  • 72
1

lists are mutable, whereas the number isn't. More examples here http://inst.eecs.berkeley.edu/~selfpace/cs9honline/Q2/mutation.html

vkris
  • 2,095
  • 7
  • 22
  • 30
0

Assigning to x inside your add() function creates a new variable. This is one of Python's quirks.

Here is a workaround:

mat = []
x = 5
def add(c,b):
        global x # do not define a local 'x'
        print c+b
        x = 8
        mat.append(c)
        mat.append(b)
add(5,6)
add(8,9)
print mat
print x
Chui Tey
  • 5,436
  • 2
  • 35
  • 44