By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,732 Members | 1,429 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,732 IT Pros & Developers. It's quick & easy.

Why does changing 1 list affect the other?

P: n/a
oom
I am a bit of a newbie when it comes to python, when working with
lists today I noticed some very odd behaviour, any suggestions
welcome:

Python 2.2.3 (#1, Nov 6 2003, 14:12:38)
[GCC 3.3.2 20031022 (Gentoo Linux 3.3.2-r2, propolice)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
firstlist=['item1','item2','item2']
secondlist=firstlist
print (firstlist,secondlist) (['item1', 'item2', 'item2'], ['item1', 'item2', 'item2']) firstlist[0]='strangeness'
print (firstlist,secondlist) (['strangeness', 'item2', 'item2'], ['strangeness', 'item2', 'item2'])


why does altering one list affect the other list ? it is driving me
insane!

Jul 18 '05 #1
Share this Question
Share on Google+
15 Replies


P: n/a
oom <oo*@xxnospamxx.ps.gen.nz> wrote:
I am a bit of a newbie when it comes to python, when working with
lists today I noticed some very odd behaviour, any suggestions
welcome:

Python 2.2.3 (#1, Nov 6 2003, 14:12:38)
[GCC 3.3.2 20031022 (Gentoo Linux 3.3.2-r2, propolice)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
firstlist=['item1','item2','item2']
secondlist=firstlist
print (firstlist,secondlist) (['item1', 'item2', 'item2'], ['item1', 'item2', 'item2']) firstlist[0]='strangeness'
print (firstlist,secondlist) (['strangeness', 'item2', 'item2'], ['strangeness', 'item2', 'item2'])


why does altering one list affect the other list ? it is driving me
insane!


Because when you say secondlist = firstlist, you're not making a copy of
the list, you're just making another reference to the existing list
object. If you're used to C/C++, think of it as passing a pointer
around.

If you really wanted to make a new list, you should look at the copy
module (specifically copy.deepcopy). Or, somewhat simplier, you could
have just said secondlist = list (firstlist), which creates a new one
(kind of like a copy constructor might do in C++).
Jul 18 '05 #2

P: n/a
On Thu, 06 Nov 2003 16:36:08 +1300, oom wrote:
firstlist=['item1','item2','item2']
Creates a list object, containing three string objects, and binds the
name 'firstlist' to the list object.
secondlist=firstlist
Binds the name 'secondlist' to the same list object.
print (firstlist,secondlist) (['item1', 'item2', 'item2'], ['item1', 'item2', 'item2'])
Outputs the same list object twice, since it is bound to both
'firstlist' and 'secondlist'.
firstlist[0]='strangeness'
Alters the list object.
print (firstlist,secondlist) (['strangeness', 'item2', 'item2'], ['strangeness', 'item2', 'item2'])


Outputs the same list object twice, since it is bound to both
'firstlist' and 'secondlist'.
why does altering one list affect the other list ? it is driving me
insane!


Because there's only one list, with two different names. This is a
result of 'secondlist = firstlist'.

What you probably want os to take a *copy* of the list object, and bind
'secondlist' to that new object. This occurs automatically for some
types (e.g. scalars) but not lists or dicts or other structured types.
import copy
firstlist = [ 'item1', 'item2', 'item3' ]
secondlist = copy.copy( firstlist )
print( firstlist, secondlist ) (['item1', 'item2', 'item3'], ['item1', 'item2', 'item3']) firstlist[0] = 'no_strangeness'
print( firstlist, secondlist ) (['no_strangeness', 'item2', 'item3'], ['item1', 'item2', 'item3'])


--
\ "It is hard to believe that a man is telling the truth when you |
`\ know that you would lie if you were in his place." -- Henry L. |
_o__) Mencken |
Ben Finney <http://bignose.squidly.org/>
Jul 18 '05 #3

P: n/a
oom
On Wed, 05 Nov 2003 23:05:30 -0500, Roy Smith <ro*@panix.com> wrote:
oom <oo*@xxnospamxx.ps.gen.nz> wrote:
I am a bit of a newbie when it comes to python, when working with
lists today I noticed some very odd behaviour, any suggestions
welcome:

Python 2.2.3 (#1, Nov 6 2003, 14:12:38)
[GCC 3.3.2 20031022 (Gentoo Linux 3.3.2-r2, propolice)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> firstlist=['item1','item2','item2']
>>> secondlist=firstlist
>>> print (firstlist,secondlist)

(['item1', 'item2', 'item2'], ['item1', 'item2', 'item2'])
>>> firstlist[0]='strangeness'
>>> print (firstlist,secondlist)

(['strangeness', 'item2', 'item2'], ['strangeness', 'item2', 'item2'])
>>>


why does altering one list affect the other list ? it is driving me
insane!


Because when you say secondlist = firstlist, you're not making a copy of
the list, you're just making another reference to the existing list
object. If you're used to C/C++, think of it as passing a pointer
around.

If you really wanted to make a new list, you should look at the copy
module (specifically copy.deepcopy). Or, somewhat simplier, you could
have just said secondlist = list (firstlist), which creates a new one
(kind of like a copy constructor might do in C++).


Well thanks to both Ben and Roy!!

I suspected something like this was going on, but what a head
scratching session I had!

This is a very active NG ;-)

problem solved

Jul 18 '05 #4

P: n/a
Hello,
why does altering one list affect the other list ? it is driving me
insane!

In Python everything is a reference (pointer in C/C++ terms). When you
do list1 = list2 then list1 and list2 point to the same list object.
Change one and the other will see it.
If you want a copy you can either use the copy module or slicing
list1 = [1,2,3]
list2 = list1[:] # Create a shallow copy
list1[0] = "What's up doc?"
list2[0] 1 list1[0] "What's up doc?"

Do read the tutorial (http://www.python.org/doc/current/tut/tut.html)
it does a very good job at explaining thinks like that.

HTH.
Miki
Jul 18 '05 #5

P: n/a
oom <oo*@xxnospamxx.ps.gen.nz> wrote in message news:<8u********************************@4ax.com>. ..
why does altering one list affect the other list ? it is driving me
insane!


Because both variables refer to the same object (the list object).
You can check if 2 variables refer to same object with 'is' operator:
a = 3
b = a
a is b True b = 2 + b
a is b False a 3 b 5

Now, when you later think you're changing b's number, you're
actually constructing a new number object and making b refer to it.
Here 2 + b creates the new object, 5, and "b=..." assigns this object
to variable b. Two objects can be different even though they have
the same value:
a = 1000 # 1000 constructs a number object that has value 1000
b = 1000
a == b # do a & b have the same value? True a is b # do a & b refer to the same object? False

Doing this with integers smaller than 100 may be confusing
though:
a = 50 # surprise: 50 doesn't construct a new number object.
b = 50 # It just selects a commonly shared 50-object
a is b True

Python handles small numbers by sharing the same object to make
the implementation more efficient.

Variables and objects must be understood being separate
things so that you'll see what's happening. In your example, you only
did a simple assignment that made two variables refer to the same list.
You could then modify this same list through either variable.

Like the number addition example above, you could do:
a = [1, 2, 3]
b = [] + a
a[0] = 5
a [5, 2, 3] b [1, 2, 3]

Where []+a creates again a new list object, concatenation of empty
list and a. Thus a and b won't refer to same object, and changin
a's contents doesn't show as a change when you check b's contents
(or more precisely, the contents of the object that b refers to).

But the preferred way to create a copy of a list is this:
b = a[:]


You'll need to look up how "slicing" works to know what this one
actually does.
Jul 18 '05 #6

P: n/a

"Ben Finney" <bi****************@and-benfinney-does-too.id.au> wrote in
message news:sl*******************************@iris.polar. local...
On Thu, 06 Nov 2003 16:36:08 +1300, oom wrote:
> firstlist=['item1','item2','item2']
Creates a list object, containing three string objects, and binds the
name 'firstlist' to the list object.
secondlist=firstlist
Binds the name 'secondlist' to the same list object.
print (firstlist,secondlist)

(['item1', 'item2', 'item2'], ['item1', 'item2', 'item2'])


Outputs the same list object twice, since it is bound to both
'firstlist' and 'secondlist'.
> firstlist[0]='strangeness'
Alters the list object.
print (firstlist,secondlist)

(['strangeness', 'item2', 'item2'], ['strangeness', 'item2', 'item2'])


Outputs the same list object twice, since it is bound to both
'firstlist' and 'secondlist'.
why does altering one list affect the other list ? it is driving me
insane!


Because there's only one list, with two different names. This is a
result of 'secondlist = firstlist'.

What you probably want os to take a *copy* of the list object, and bind
'secondlist' to that new object. This occurs automatically for some
types (e.g. scalars) but not lists or dicts or other structured types.


[snip]

I used to think this too: different types work differently. Now I think that
the only difference is that some types are immutable. Consider:
x = 5
y = x
print x, y 5 5 x = 4
print x, y 4 5

That's sort of what one might expect. But lists work differently. Or do
they?
x = [5]
y = x
print x, y [5] [5] x = [4]
print x, y [4] [5]

Scalars and lists work the same! And yet:
x = [5]
y = x
print x, y [5] [5] x[0] = 4
print x, y

[4] [4]

What's going on? The model is:

x = <thing>
y = x
print x is y
True
<edit x if it is mutable> # edit, not reassign
print x is y
True
x = <anotherthing> # reassign x
print x is y
False

AFAIK that works for all types. The only difference is that with immutable
data types you can't even try the editing part.

--
Cy
http://home.rochester.rr.com/cyhome/
Jul 18 '05 #7

P: n/a
On Fri, 07 Nov 2003 03:00:29 GMT, Cy Edmunds wrote:
"Ben Finney" <bi****************@and-benfinney-does-too.id.au> wrote:
What you probably want os to take a *copy* of the list object, and
bind 'secondlist' to that new object. This occurs automatically for
some types (e.g. scalars) but not lists or dicts or other structured
types.
I used to think this too: different types work differently. Now I
think that the only difference is that some types are immutable.


Your examples aren't showing this:
Consider:
x = 5
y = x
print x, y 5 5 x = 4
print x, y 4 5
Creating a new integer object, 4, and binding 'x' to that.
x = [5]
y = x
print x, y [5] [5] x = [4]
print x, y [4] [5]


Creating a new list object, [4], and binding 'x' to that.
Scalars and lists work the same! And yet:


For binding to a new object, sure. The difference was the conceptual
"modify" operation:
x = [ 1, 2, 3 ]
y = x
print x, y [1, 2, 3] [1, 2, 3] x[0] = 55
print x, y

[55, 2, 3] [55, 2, 3]

There's no equivalent for integer objects, because they're not mutable.
I think we're in agreement, though I may have been remiss in failing to
distinguish the extra operations available to mutable types.

--
\ "A good politician is quite as unthinkable as an honest |
`\ burglar." -- Henry L. Mencken |
_o__) |
Ben Finney <http://bignose.squidly.org/>
Jul 18 '05 #8

P: n/a
"Ben Finney" <bi****************@and-benfinney-does-too.id.au> wrote in
message news:sl*******************************@iris.polar. local...
On Fri, 07 Nov 2003 03:00:29 GMT, Cy Edmunds wrote:
"Ben Finney" <bi****************@and-benfinney-does-too.id.au> wrote:
What you probably want os to take a *copy* of the list object, and
bind 'secondlist' to that new object. This occurs automatically for
some types (e.g. scalars) but not lists or dicts or other structured
types.


I used to think this too: different types work differently. Now I
think that the only difference is that some types are immutable.


Your examples aren't showing this:
Consider:
> x = 5
> y = x
> print x, y

5 5
> x = 4
> print x, y

4 5


Creating a new integer object, 4, and binding 'x' to that.
> x = [5]
> y = x
> print x, y

[5] [5]
> x = [4]
> print x, y

[4] [5]


Creating a new list object, [4], and binding 'x' to that.
Scalars and lists work the same! And yet:


For binding to a new object, sure. The difference was the conceptual
"modify" operation:
>>> x = [ 1, 2, 3 ]
>>> y = x
>>> print x, y [1, 2, 3] [1, 2, 3] >>> x[0] = 55
>>> print x, y [55, 2, 3] [55, 2, 3]

There's no equivalent for integer objects, because they're not mutable.
I think we're in agreement, though I may have been remiss in failing to
distinguish the extra operations available to mutable types.


I think you were remiss in saying:

"What you probably want os to take a *copy* of the list object, and bind
'secondlist' to that new object. This occurs automatically for some
types (e.g. scalars) but not lists or dicts or other structured types."

Scalars do NOT automatically make a copy.

Try this:
x = 5
y = x
print x is y

True

y is second reference to the immutable value 5, not a copy.

--
Cy
http://home.rochester.rr.com/cyhome/
Jul 18 '05 #9

P: n/a
On Fri, 07 Nov 2003 04:03:27 GMT, Cy Edmunds wrote:
Scalars do NOT automatically make a copy.


True, they can't be modified at all, so the only assignment operation
that makes sense is to assign a new value entirely. This was obscured
in my summary of the issue.

So, yes, "mutable objects can be modified" is the better starting point.

--
\ "Faith may be defined briefly as an illogical belief in the |
`\ occurrence of the improbable." -- Henry L. Mencken |
_o__) |
Ben Finney <http://bignose.squidly.org/>
Jul 18 '05 #10

P: n/a
Cy Edmunds wrote:
Try this:
x = 5
y = x
print x is y True

y is second reference to the immutable value 5, not a copy.


As an aside, you cannot reliably test Python's general behaviour for
immutable types with small integers (-5 <= i <= 99), as every literal in
this range will refer to the same instance:
x = 5
y = 5
x is y True

But:
x = 100
y = 100
x is y

False

Peter
Jul 18 '05 #11

P: n/a
In article <sl*******************************@iris.polar.loca l>,
Ben Finney <bi****************@and-benfinney-does-too.id.au> wrote:
Consider:
> x = 5
> y = x <--- here. A new '5' is created for y to bind to??
> print x, y

5 5
> x = 4
> print x, y

4 5


Creating a new integer object, 4, and binding 'x' to that.


Equally important:

A _new_ object '5' is created in step 2 and y is bound to that. That's
not what happens with the lists:
> x = [5]
> y = x <--- here. A new list is NOT created for y to bind to
> print x, y

[5] [5]
> x = [4]
> print x, y

[4] [5]


In the list example BOTH x and y are bound to the list [5]. It's the
differences in step 2 (y=x) that throws beginners (did me).

Now I'm confusing myself.
Jul 18 '05 #12

P: n/a
In article <jQ*******************@twister.nyroc.rr.com>,
"Cy Edmunds" <ce******@spamless.rochester.rr.com> wrote:
Try this:
x = 5
y = x
print x is y

True

y is second reference to the immutable value 5, not a copy.


So the action is on the binding end? Only one 5 is created, but the x=4
following statement UNbinds x and rebinds it to '4', rather than
changing the object. y remains bound to '5'. Did that come out right?

Then for lists, when we do x[0]=4 we are NOT unbinding x, but rather
just changing the object?

Sounds like if we try harder we will get to the _binding_ actions of the
'=' operator. Let me try harder right here (off the top of my head).

So, let's see, we view '=' as a binding operation.

x=list

binds x to the list, but each list element is bound to something else (I
refer to this as a second level binding).

For lists we are allowed to change that second level binding. This
second level action does NOT affect the first level y=x binding.

Now, does that sound right? Anyone?

-- Lou Pecora
Jul 18 '05 #13

P: n/a
"Louis Pecora" <pe****@anvil.nrl.navy.mil> wrote in message
news:pe**************************@ra.nrl.navy.mil. ..
So the action is on the binding end? Only one 5 is created, but the x=4
following statement UNbinds x and rebinds it to '4', rather than
changing the object. y remains bound to '5'. Did that come out right?

Then for lists, when we do x[0]=4 we are NOT unbinding x, but rather
just changing the object?

Sounds like if we try harder we will get to the _binding_ actions of the
'=' operator. Let me try harder right here (off the top of my head).

So, let's see, we view '=' as a binding operation.

x=list

binds x to the list, but each list element is bound to something else (I
refer to this as a second level binding).

For lists we are allowed to change that second level binding. This
second level action does NOT affect the first level y=x binding.

Now, does that sound right? Anyone?

-- Lou Pecora


This "first order, second order" binding is just confusing things, I think.

Try this:

There are two kinds of "things" in Python--names and objects.

1) Names point to objects, and only to objects
2) Names are not objects.

It follows from this that names never point to names, AND that objects can
CONTAIN names. So, names are THINGS, but not OBJECTS. Names are like
arrows that you can hold and point at things with, but that can't be pointed
to.

If you say something like "y = x", you're saying, "whatever object x points
to, make y point to the *same* object." (NOT a *copy* of that object!)

Further, some names are explicit, some implicit (or "anonymous," if you
don't mind the slight contradiction that entails....). Container objects
(dictionaries, lists, tuples) contain "anonymous names" which point to
objects. These implicit names are accessed indirectly only by an index or
key, not directly by a name in a namespace.

If the container is "mutable", then the implicit names contained within the
container object can be made to point to different objects after the
container object's creation.

This is the behavior we see in a list:
firstlist=['item1','item2','item2'] Make a list-type container object with three implicit names. Make those
implicit names point to three different string objects.
Then make the name firstlist point to that just-created list object. secondlist=firstlist Make a name secondlist which points to the same list firstlist points to. print (firstlist,secondlist) (['item1', 'item2', 'item2'], ['item1', 'item2', 'item2'])
Create a tuple-type container object, with two implicit names, which point
to the objects pointed to by firstlist and secondlist (which end up being
the same identical object.)
Note that this tuple is never bound to a name, so it will be garbage
collected eventually. firstlist[0]='strangeness' Make the zeroth implicit name (which is contained in the object pointed to
by "firstlist") point at the new string object 'strangeness'. print (firstlist,secondlist)

(['strangeness', 'item2', 'item2'], ['strangeness', 'item2', 'item2'])
firstlist and secondlist *still* point to the same object. It's just that
the object was changed.

--
Francis Avila
Jul 18 '05 #14

P: n/a
In article <vq************@corp.supernews.com>,
"Francis Avila" <fr***********@yahoo.com> wrote:
"Louis Pecora" <pe****@anvil.nrl.navy.mil> wrote in message
news:pe**************************@ra.nrl.navy.mil. ..
So the action is on the binding end? Only one 5 is created, but the x=4
following statement UNbinds x and rebinds it to '4', rather than
changing the object. y remains bound to '5'. Did that come out right?

Then for lists, when we do x[0]=4 we are NOT unbinding x, but rather
just changing the object?

Sounds like if we try harder we will get to the _binding_ actions of the
'=' operator. Let me try harder right here (off the top of my head).

So, let's see, we view '=' as a binding operation.

x=list

binds x to the list, but each list element is bound to something else (I
refer to this as a second level binding).

For lists we are allowed to change that second level binding. This
second level action does NOT affect the first level y=x binding.

Now, does that sound right? Anyone?

-- Lou Pecora


This "first order, second order" binding is just confusing things, I think.

Try this:

There are two kinds of "things" in Python--names and objects.

1) Names point to objects, and only to objects
2) Names are not objects.

It follows from this that names never point to names, AND that objects can
CONTAIN names. So, names are THINGS, but not OBJECTS. Names are like
arrows that you can hold and point at things with, but that can't be pointed
to.

If you say something like "y = x", you're saying, "whatever object x points
to, make y point to the *same* object." (NOT a *copy* of that object!)

Further, some names are explicit, some implicit (or "anonymous," if you
don't mind the slight contradiction that entails....). Container objects
(dictionaries, lists, tuples) contain "anonymous names" which point to
objects. These implicit names are accessed indirectly only by an index or
key, not directly by a name in a namespace.

If the container is "mutable", then the implicit names contained within the
container object can be made to point to different objects after the
container object's creation.


I see what you mean. But I don't see that this is any simpler than what
I said, above. Maybe just style. I think both 'explanations' are
stating essentially that container objects point 'further' to a
collection of objects (my second level, your implicit names).

I think it helped to see another take on this. Thanks.

-- Lou Pecora
Jul 18 '05 #15

P: n/a
Louis Pecora <pe****@anvil.nrl.navy.mil> writes:
In article <sl*******************************@iris.polar.loca l>,
Ben Finney <bi****************@and-benfinney-does-too.id.au> wrote:
Consider:

>>> x = 5
>>> y = x <--- here. A new '5' is created for y to bind to?? [snipped]
Equally important:

A _new_ object '5' is created in step 2 and y is bound to that.


Wrong (and the source of your confusion).

x and y are the *same* object. You just gave two different *names* to the same
object. So here:
x = 3
y = x
a = [3]
b = a
we have *2* objects (3 and [3]), each of which can be refered to by 2
different names (x and y for 3 and a and b for [3]).

This means that if we *modify the underlying object* e.g:
a.append(4)
....then regardless by which of the names we given it we call it, we will get
the same result:
a [3, 4] b [3, 4]

However, there is no way to modify numbers (a list can grow longer, but the
number 3 can never become the number 4), the same can't happen with numbers.

For example:
x + 4 7

gives you a new and different number (with the value 7), the number the name x
refers to is not modified.
x 3

Its exactly the same in this case:
x = x + 4
Verbosely you could translate the above as: "let the name x refer to the *new*
number that is obtained from adding 3 and what the name x currently refers
to".

Obviously, this in no way affects what the name y refers to.
y 3

But x now names a *different* object, the number 7.
x 7

Same for lists:
a = a + [5]
a [3, 4, 5]
b

[3, 4]

The key difference you need to understand is that between changing *which
object* one particular name refers (``name = something``) and *changing the
object* one (or many) names refer to (``name.change_me_somehow()``).

'as
Jul 18 '05 #16

This discussion thread is closed

Replies have been disabled for this discussion.