-1

I have the following code:

def proc2(p):
    p=p+[1]
y=[2,5]
proc2(y)
print(y)


z=[2,5]
z=z+[1]
print(z)

The output of the code is:

[2, 5]
[2, 5, 1]

I understand that y is not modified to [2,5,1]. But, y is reassigned to a new list, which is [2,5,1], right? Then why does y still refer to the original value? If the value of z has changed, why not y?

P.S. I have just asked a question which is almost the same as this one. That question has been marked as a duplicate of another question. However, I think they are a bit different. That is why I'm posting my question again. I think I must have missed something about function.

failbetter
  • 143
  • 1
  • 9
  • In `proc2()`, The `p` list is appended and then `p` is reassigned to the longer list. As you mentioned, this does not affect `y` which is still pointing to the shorter list. However, in your second example, `z` is actually reassigned to point to the appended list. – Phylogenesis Nov 24 '17 at 12:59
  • 1
    The value of the original list assigned to `z` actually *hasn't* changed. You're simply not referencing it any more. If you did e.g. `old_z = z` *before* `z += 1`, then printed `old_z` afterwards, you'd see that. There's no difference in behaviour. – jonrsharpe Nov 24 '17 at 13:00
  • `p=p+[1]` does not modify the list that `p` was previously referencing. It modifies the _variable_ `p` to reference a new list. Another variable, still referencing the _old_ list, will not be affected. – khelwood Nov 24 '17 at 13:07
  • @jonrsharpe What you said, I have fully understood. But, after running `proc2(y)`, y should have now pointed to the new list `[2,5,1]`. Why then, when I print y, does python say y still points to `[2,5]`? – failbetter Nov 25 '17 at 09:16
  • Because it does still reference the old list? Only the local variable p got reassigned. – jonrsharpe Nov 25 '17 at 09:25

4 Answers4

0

Your variable y is not changed because you change the variable p, which is local to your function. This variable has nothing to do with y after the function ends.

Sqoshu
  • 944
  • 2
  • 9
  • 16
0

Two options:

  1. Either have your function return the new list:

    def proc2(p):
        return p + [1]
    
  2. Or, have it modify the p in-place (and optionally return it for cleaner coding):

    def proc2(p):
        p += [1]  # this is not exactly the same as p = p + [1]
        return p  # <- optional!
    

Your code, instead of modifying the existing p, it creates a new one which is however not communicated to the outer scope; and as a result dies when the function quits.

Ma0
  • 15,057
  • 4
  • 35
  • 65
0

y is reassigned to a new list

No, there's only one y = ... assignment in your code.

What happens when your function executes is the following:

# implicitly: assign formal parameter name to actual argument value
p = y

# compute p + [1] => [2, 5, 1]
# assign the result to the name p
p = p + [1]

# aaaand... nothing from here on.

So your function computes a result (a new list), assigns the name p inside the function scope, and then p is lost as soon as the function exits.

If you don't want to write a function that mutates your input list, you need to return the computed value and re-assign the name y to see the desired effect.

>>> def proc2(p):
...     p = p + [1]
...     return p
... 
>>> y = [2,5]
>>> y = proc2(y)
>>> y
[2, 5, 1]

Note that even if you had an y = ... assignment inside your function, that name would be local to the function and the outer scope would not care:

>>> def proc2(y):
...     y = y + [1]
... 
>>> y = [2,5]
>>> proc2(y)
>>> y
[2, 5]

Finally, you could tell Python that you mean the global y inside your functions body, but that's considered poor style (definitely here and in most other cases).

>>> def proc2():
...     global y
...     y = y + [1]
... 
>>> y = [2,5]
>>> proc2()
>>> y
[2, 5, 1]
timgeb
  • 76,762
  • 20
  • 123
  • 145
  • I agree with all you said, except "If you don't want to write a function that mutates your input list". Like what @jonrsharpe mentioned, the value of the original list assigned to `p`, i.e. the input list [2, 5], actually hasn't been mutated. It's just `p` got reassigned to another list [2, 5, 1]. Do you agree? – failbetter Nov 25 '17 at 10:57
  • @failbetter I never claimed that your original function mutates your input list. I wanted to say that you have to return a value in order for your function to do something useful *unless* you mutate the input argument. – timgeb Nov 25 '17 at 15:11
0

To better understand what happens here, check ids of z and y, they are different, which means z and y are different objects. Changing one of them does not affect the other.

y=[1,2] z=[1,2] print id(y), id(z)

aliowka
  • 31
  • 2