4

Why is it that:

 >>> a = 1
 >>> b = a
 >>> a = 2
 >>> print(a)
 2
 >>> print(b)
 1

...but:

 >>> a = [3, 2, 1]
 >>> b = a
 >>> a.sort()
 >>> print(b)
 [1, 2, 3]

I mean, why are variables really copied and iterators just referenced?

Laurent
  • 539
  • 1
  • 5
  • 11
  • 1
    In my opinion this is one of the hardest parts of learning Python: Learning to tell the difference between when you are *taking an existing object and modifying it* and when you are *taking an existing name and making it point to a different object* – turbulencetoo Nov 12 '15 at 23:12
  • @turbulencetoo: it is simple. None of the examples *copy* objects here. Objects may have multiple names. Names may refer to different objects at different times. [This picture might provide an insight](http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#python-has-names) – jfs Nov 13 '15 at 03:25

3 Answers3

7

Variables are not "really copied". Variables are names for objects, and the assignment operator binds a name to the object on the right hand side of the operator. More verbosely:

>>> a = 1 means "make a a name referring to the object 1".

>>> b = a means "make b a name referring to the object currently referred to by a. Which is 1.

>>> a = 2 means "make a a name referring to the object 2". This has no effect on which object anything else that happened to refer to 1 now refers to, such as b.

In your second example, both a and b are names referring to the same list object. a.sort() mutates that object in place, and because both variables refer to the same object the effects of the mutation are visible under both names.

Peter DeGlopper
  • 36,326
  • 7
  • 90
  • 83
  • See also the lengthier and more detailed discussions on these answers: http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference and http://stackoverflow.com/questions/534375/passing-values-in-python – Peter DeGlopper Nov 12 '15 at 23:09
  • I think it would also be worth while having a short explanation of mutability and why, say, `a+=1` will not also change `b` when b and a are ints but `a+=[1]` will if a and b are both lists – R Nar Nov 12 '15 at 23:11
2

Think of the assigned variables as pointers to the memory location where the values are held. You can actually get the memory location using id.

a = 1
b = a

>>> id(a)
4298171608

>>> id(b)
4298171608  # points to the same memory location

a = 2
>>> id(a)
4298171584  # memory location has changed

Doing the same with your list example, you can see that both are in fact operating on the same object, but with different variables both pointing to the same memory location.

a = [3, 2, 1]
b = a
a.sort()

>>> id(a)
4774033312

>>> id(b)
4774033312  # Same object
Alexander
  • 105,104
  • 32
  • 201
  • 196
  • 1
    Note that `id` returning a memory location is an implementation detail - true for the common C python implementation, but not guaranteed to be true in all implementations. It is reliably true that if the `id`s of two objects are the same, the objects are the same. What `id` means for immutable objects like integers and strings is a more complicated question - generally nothing you should ever have to care about, since they are immutable. – Peter DeGlopper Nov 12 '15 at 23:12
0

in your first example you've reassigned a's value after making b's value a. so a and b carry different values.

the same would've occurred in your second example if you had reassigned a to a new sorted list instead of just sorting it in place.

a = [3,2,1]
b = a
a.sort()
print b
[1,2,3]

but...

a = [3,2,1]
b = a
sorted(a)
print b
[3,2,1]
pyne
  • 507
  • 1
  • 5
  • 16