Why does changing 1 list affect the other?

O

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!
 
B

Ben Finney

firstlist=['item1','item2','item2']

Creates a list object, containing three string objects, and binds the
name 'firstlist' to the list object.

Binds the name 'secondlist' to the same list object.
(['item1', 'item2', 'item2'], ['item1', 'item2', 'item2'])

Outputs the same list object twice, since it is bound to both
'firstlist' and 'secondlist'.

Alters the list object.
(['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'])
>>>
 
R

Roy Smith

oom said:
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++).
 
O

oom

oom said:
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
 
M

Miki Tebeka

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
 
H

Hannu Kankaanp??

oom said:
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:
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:
False

Doing this with integers smaller than 100 may be confusing
though:
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:

You'll need to look up how "slicing" works to know what this one
actually does.
 
C

Cy Edmunds

Ben Finney said:
firstlist=['item1','item2','item2']

Creates a list object, containing three string objects, and binds the
name 'firstlist' to the list object.

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:
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.
 
B

Ben Finney

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:

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.
 
C

Cy Edmunds

Ben Finney said:
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:

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:
True

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

Ben Finney

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.
 
P

Peter Otten

Cy said:
Try this:

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:
True

But:
False

Peter
 
L

Louis Pecora

Consider:

4 5

Creating a new integer object, 4, and binding 'x' to that.
[/QUOTE]

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.
 
L

Louis Pecora

"Cy Edmunds said:
Try this:

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
 
F

Francis Avila

Louis Pecora said:
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.(['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.
Make the zeroth implicit name (which is contained in the object pointed to
by "firstlist") point at the new string object 'strangeness'.(['strangeness', 'item2', 'item2'], ['strangeness', 'item2', 'item2'])
firstlist and secondlist *still* point to the same object. It's just that
the object was changed.
 
L

Louis Pecora

"Francis Avila said:
Louis Pecora said:
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
 
A

Alexander Schmolck

[snipped]
Equally important:

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

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:

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:

....then regardless by which of the names we given it we call it, we will get
the same result:
[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:
7

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

Its exactly the same in this case:

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.
3

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

Same for lists:
[3, 4, 5]
[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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top