Why is this?

J

Jiri Barton

Hi everyone,

I have a problem with initialization.
[1]

Why is this? Why does not this behave like the below:
[]

And, just to add to my confusion:
[[]]*2 [[], []]
[[], []] == [[]]*2
True

Thanks in advance for the explanation.
jbar


BTW, if it matters...
Python 2.4.1 (#2, Mar 30 2005, 20:41:35)
[GCC 3.3.5 (Debian 1:3.3.5-8ubuntu2)] on linux2
 
M

Matt Hammond

Hi Jiri,

I have a problem with initialization.
a, b = [[]]*2
a.append(1)
b
[1]

Why is this? Why does not this behave like the below:
a, b = [[], []]
a.append(1)
b
[]

In the first case, you make a list containing a single empty list. The
"*2" operation duplicates the item in that list. So now both a and b
contain the same instance of an empty list. Whereas in the second case,
you explicity declare two separate instances of an empty list.

The append method modifys the existing list object - it changes the values
it holds inside itself. Therefore, in the first example, because a and b
both refer to the same object, changing 'a' will will appear to also
change 'b'. The same is not true of the second example, because they are
different objects.

A simpler example:

Now lets try some tests:
True

Ok - so this shows that a and b, and b and c are equal _in the sense that
they amount to the same value_. But that doesn't mean they are the same
actual object:
True

b and c are the same empty list object. But a and b are separate,
different, empty list objects.

Why the difference? Imagine you made a set of objects to represent some
kind of numeric values, eg. vectors. Asking "A==B" means "is the value of
the vector A, the same as the value of the vector B". But asking "A is B"
means "is the object A the same object as B".
[[]]*2 [[], []]
[[], []] == [[]]*2
True

Same effect. But try the 'is' operator, to see if they are actually the
same instances of 'empty list':



Hope this helps ... its my first go at explaining this kind of stuff, so
apologies if it isn't as clear as it could be!



Matt
 
J

Jiri Barton

Yes, now it is clear!

As always, I should have RTFM, the operator* is not just a syntactic sugar
and thus does not make copies. You know, my actual scenario was with four
variables at the time:

a, b, c, d = [], [], [], []

so I was even more tempted to use the previous and wrong approach:)

Thank you for your explanation. No more errors in my code from now on (oh
well,...)

jbar
 
P

Paolino

Jiri said:
Hi everyone,

I have a problem with initialization.
a, b = [[]]*2
a.append(1)
b
[1]

Why is this? Why does not this behave like the below:
>>> a, b = [[]]*2
>>> a==b
True
And, just to add to my confusion:


[[], []]

True
This confuses me also,looks like empty lists share same object.

Paolino






___________________________________
Yahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB
http://mail.yahoo.it
 
P

Paolino

Paolino said:
Jiri said:
Hi everyone,

I have a problem with initialization.

a, b = [[]]*2
a.append(1)
b

[1]

Why is this? Why does not this behave like the below:
a, b = [[]]*2
a==b
True Ooops I should write 'a is b'

And, just to add to my confusion:



[[], []]

[[], []] == [[]]*2

True

This confuses me also,looks like empty lists share same object.
This is actually OK as lists are compared for their contents ;-)
Paolino






___________________________________
Yahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB
http://mail.yahoo.it


___________________________________
Aggiungi la toolbar di Yahoo! Search sul tuo Browser, e'gratis!
http://it.toolbar.yahoo.com
 
J

Jan-Ole Esleben

For the sake of completeness (I didn't copy this message to the list):
I have a problem with initialization.
a, b = [[]]*2
a.append(1)
b
[1]

Why is this? Why does not this behave like the below:

You create a single list (inside your brachets) and duplicate a
reference to it. a and b are two references to the same list; this is
just a problem for mutable objects, but I think it's safe to say that
it bites everyone at some point.

Obviously, this is not a test for referential identity.

Hope this helps to clear the matter up!
Ole


2005/8/10 said:
Yes, now it is clear!

As always, I should have RTFM, the operator* is not just a syntactic sugar
and thus does not make copies. You know, my actual scenario was with four
variables at the time:

a, b, c, d = [], [], [], []

so I was even more tempted to use the previous and wrong approach:)

Thank you for your explanation. No more errors in my code from now on (oh
well,...)

jbar
 
B

Bryan Olson

Jiri said:
> Yes, now it is clear!
>
> As always, I should have RTFM, the operator* is not just a syntactic sugar
> and thus does not make copies.

That issue bites, like, everyone.
> You know, my actual scenario was with four
> variables at the time:
>
> a, b, c, d = [], [], [], []

Incidentally, to create a list of 37 distinct empty lists, you
can use:

[[] for _ in range(37)]
 
P

phil hunt

Hi everyone,

I have a problem with initialization.
a, b = [[]]*2
a.append(1)
b
[1]

Why is this? Why does not this behave like the below:
a, b = [[], []]
a.append(1)
b
[]

In your 1st example a and b point to copies of the same object, in
the second example the point to two separate objects that happen to
have the same repr() representation.

Here's another example of the same thing:
c = []
d = [c,c]
e = [[],[]]
d [[], []]
e
[[], []]

(d) and (e) appear to be the same (i.e. they have the same repr()
form), but they are not. Consider:
[[], ['spam']]

But:
[['spam'], ['spam']]

The point is that in Python an object's repr() -- which stands for
"representation" -- doesn't actually tell you how the object is
represented inside the innards to the Python system.

Incidently I am currently working on a programming language that
fixes this problem. In my language "Unify", the equivalent of repr
is called "storage manager format" (or SM-format) because if two
values have the same SM-format it is guaranteed that the system will
treat them identiacally. The SM-format can thus be used for
serialisation, and incidently it is also the same format in which
literals are written in a program.

In Unify to specify an Array containing two separate empty Arrays
would look like this:

e := #(() ())

The code to add a value to one sub-array, and print the result is:

e[1] @= 'spam'. // means same as Python d[1].append("spam")
out << sm(e). // convert to SM-string, output it to stdout

This would print this text:

#(() (spam))

An array containing two copies of the same sub-array might look like
this:

d := #( () &[0] )

Where "&[0]" means "pointer to the 0th array subscript".
 
R

Reinhold Birkenfeld

Paolino said:
Jiri said:
Hi everyone,

I have a problem with initialization.
a, b = [[]]*2
a.append(1)
b
[1]

Why is this? Why does not this behave like the below:
a, b = [[]]*2
a==b
True

ITYM "a is b", which is also true.
And, just to add to my confusion:


[[], []]
[[], []] == [[]]*2

True
This confuses me also,looks like empty lists share same object.

Wrong. You mustn't confuse "==" and "is".
"==" doesn't test for identity. For lists, it compares them
by contents.

"[[], []] is [[]]*2" will yield False.

Reinhold
 
J

John Hazen

[[]]*2
[[], []]
[[], []] == [[]]*2
True

Same effect. But try the 'is' operator, to see if they are actually the
same instances of 'empty list':
[[], []] is [[]]*2
True

Just curious, did you actually cut and paste this from a real
interactive session? (I think not.) My interpreter (yes, I know it's
old) gives:

$ python
Python 2.3 (#1, Sep 13 2003, 00:49:11)
[GCC 3.3 20030304 (Apple Computer, Inc. build 1495)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
False

Which is, I think, the point you were trying to make.

-John
 
M

Matt Hammond

[[], []] is [[]]*2
True

Just curious, did you actually cut and paste this from a real
interactive session? (I think not.) My interpreter (yes, I know it's
old) gives:

Ooops - you're absolutely right. I was cutting and pasting, but it seems I
was a little overzealous with my editing!

I've still got that in my terminal's history buffer, and it does indeed
read:
False
 
P

Peter Mott

If I use concatenation + instead of multiplication * then I get the
result that Jiri expected:
>>> L = [[]] + [[]]
>>> L[1].append(1)
>>> L
[[], [1]]

With * both elements are changed:
>>> L = [[]] * 2
>>> L[1].append(1)
>>> L
[[1], [1]]

Alex Martelli says in his excellent Nutshell book that + is
concatenation and that "n*S is the concatenation of n copies of S". But
it seems not so. Surely, from a logical point of view, S + S should be
the same as S * 2?

Peter



The excellent Martelli Python Nutshell says that multiplication S*n is
"the concatenation of n copies of S" so S+S and S*2 would be expected to
be the same. It seems though that they are not but that * creates a list


Jiri said:
Hi everyone,

I have a problem with initialization.
a, b = [[]]*2
a.append(1)
b

[1]

Why is this? Why does not this behave like the below:

a, b = [[], []]
a.append(1)
b

[]

And, just to add to my confusion:


[[], []]

True

Thanks in advance for the explanation.
jbar


BTW, if it matters...
Python 2.4.1 (#2, Mar 30 2005, 20:41:35)
[GCC 3.3.5 (Debian 1:3.3.5-8ubuntu2)] on linux2
 
M

Matt Hammond

If I use concatenation + instead of multiplication * then I get the
result that Jiri expected:
L = [[]] + [[]]
L[1].append(1)
L
[[], [1]]

With * both elements are changed:
L = [[]] * 2
L[1].append(1)
L
[[1], [1]]

Alex Martelli says in his excellent Nutshell book that + is
concatenation and that "n*S is the concatenation of n copies of S". But
it seems not so. Surely, from a logical point of view, S + S should be
the same as S * 2?

S+S is the same as S*2, but L= [[]] + [[]] is not S+S. The two terms being
added are different instances of an empty list. You are
adding/concatenating two different object instances.

Suppose I do concatenate two of the same object instance, then I get the
same behaviour as with the multiply example:
T = [[]]
L = T + T
L[1].append(1)
L
[[1], [1]]

In fact, you could argue this is exactly what the multiply operation is
doing. (internally the implementation may be slightly different, but it is
still equivalent to this)

regards


Matt
 
D

Duncan Booth

Peter said:
If I use concatenation + instead of multiplication * then I get the
result that Jiri expected:
L = [[]] + [[]]
L[1].append(1)
L
[[], [1]]

With * both elements are changed:
L = [[]] * 2
L[1].append(1)
L
[[1], [1]]

Alex Martelli says in his excellent Nutshell book that + is
concatenation and that "n*S is the concatenation of n copies of S". But
it seems not so. Surely, from a logical point of view, S + S should be
the same as S * 2?
What you did was not S+S. You did S+T, i.e. you added two distinct lists.
Try it again adding the same list and you will see that both addition and
multplication do work the same:
S = [[]]
L = S + S
L[1].append(1)
L [[1], [1]]
S = [[]]
L = 2*S
L[1].append(1)
L
[[1], [1]]
 
P

Peter Mott

Matt said:
If I use concatenation + instead of multiplication * then I get the
result that Jiri expected:
L = [[]] + [[]]
L[1].append(1)
L
[[], [1]]

With * both elements are changed:
L = [[]] * 2
L[1].append(1)
L
[[1], [1]]

Alex Martelli says in his excellent Nutshell book that + is
concatenation and that "n*S is the concatenation of n copies of S".
But it seems not so. Surely, from a logical point of view, S + S
should be the same as S * 2?


S+S is the same as S*2, but L= [[]] + [[]] is not S+S. The two terms
being added are different instances of an empty list. You are
adding/concatenating two different object instances.

But it is still true that [[]] + [[]] is not the same as [[]] * 2. In my
usage anyway this means that "S+S is the same as S*2" is false. Because
there are Python expressions for which it is falsfied.

The problem I have is pretty philosophical I admit, but I don't think
you do it justice. It's really about identity. Logically speaking
identity is a congruence relation of a language, which means that if x=y
is true then C(x) = C(y) will be true for any context C of the lanuage.
Python is so regular that most of the time it follows this. But not with
*. If you define C(x):

def C(x):
.... x[1].append(1)
.... return x[0]

then although [[]]+[[]] == [[]]*2 evaluates true C([[]]+[[]]) is
different from C([[]]*2). So == is not a congruence in Python.
Inbteresting that Phil Hunt just posted about 'Unify' which, if I
understand it right, has the feature that provided expressions S and T
are in the canonical "Storage Manager" format then == will be a
congruence and hence an idenity.

Cheers

Peter
 
D

Duncan Booth

Peter said:
But it is still true that [[]] + [[]] is not the same as [[]] * 2. In my
usage anyway this means that "S+S is the same as S*2" is false. Because
there are Python expressions for which it is falsfied.

The problem I have is pretty philosophical I admit, but I don't think
you do it justice. It's really about identity.

So would you expect:

random.seed(0)
random.random() + random.random()

and:

random.seed(0)
random.random() * 2

to be the same? The first call to random() in each case returns the same
result, but even though the source text is identical the second call
in the addition returns something different. It is just the same with the
lists.
 
P

Peter Mott

Duncan said:
Peter Mott wrote:

But it is still true that [[]] + [[]] is not the same as [[]] * 2. In my
usage anyway this means that "S+S is the same as S*2" is false. Because
there are Python expressions for which it is falsfied.

The problem I have is pretty philosophical I admit, but I don't think
you do it justice. It's really about identity.


So would you expect:

random.seed(0)
random.random() + random.random()

and:

random.seed(0)
random.random() * 2

to be the same? The first call to random() in each case returns the same
result, but even though the source text is identical the second call
in the addition returns something different. It is just the same with the
lists.

I don't see that this bears on what I said at all.

Peter
 
M

Mike Meyer

Peter Mott said:
If I use concatenation + instead of multiplication * then I get the
result that Jiri expected:
L = [[]] + [[]]
L[1].append(1)
L
[[], [1]]

With * both elements are changed:
L = [[]] * 2
L[1].append(1)
L
[[1], [1]]

Alex Martelli says in his excellent Nutshell book that + is
concatenation and that "n*S is the concatenation of n copies of
S". But it seems not so. Surely, from a logical point of view, S + S
should be the same as S * 2?

Only if you think lists are numbers. They aren't. The only real
resemblance between the operators on lists and numbers is that the
symbols got overloaded for both types. The operators on lists aren't
commutative, aren't associative, and don't have inverses. Given that,
the surprising thing is that S + S is the same as S * 2 as often as it
is.

<mike
 

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

Forum statistics

Threads
473,794
Messages
2,569,641
Members
45,353
Latest member
RogerDoger

Latest Threads

Top