append on lists

F

Fredrik Lundh

Armin said:
just a dumb question.

Let a = [1,2,3,4,5]

Why is the value of a.append(7) equal None and not [1,2,3,4,5,6,7] ??

yeah, that's a dumb question.

</F>
 
C

Chris Rebert

Hi,

just a dumb question.

Let a = [1,2,3,4,5]

Why is the value of a.append(7) equal None and not [1,2,3,4,5,6,7] ??
I'll assume the presence of the 6 is a typo.

Because .append() mutates 'a' and appends the item in-place rather
than creating and returning a new list with the item appended, and
it's good Python style for mutating methods to have no return value
(since all functions must have some return value, Python uses None
when the function doesn't explicitly return anything).

If you print 'a' after doing the .append(), you'll see it's changed to
your desired value.

Regards,
Chris
 
A

Arnaud Delobelle

Hi,

just a dumb question.

Let a = [1,2,3,4,5]

Why is the value of a.append(7) equal None and not [1,2,3,4,5,6,7] ??

--Armin

Because list.append is a method that mutates its object, and such
method usually return None. What you should check is the value of 'a'
after 'a.append(7)'.
 
A

Armin

Hi,

just a dumb question.

Let a = [1,2,3,4,5]

Why is the value of a.append(7) equal None and not [1,2,3,4,5,6,7] ??

--Armin
 
F

Fredrik Lundh

Armin said:
> If d should reference the list a extended with a single list element
> you need at least two lines
>
> a.append(7)
> d=a

why do you need two names for the same thing?
and not more intuitive d = a.append(7)

unless you completely change the semantics of "append", your code would
modify "a" as well. how is that "more intuitive"?

side effects are bad as they are, but side effects in unexpected places
is a really lousy idea. I don't think you've thought this one through,
really.

</F>
 
A

Armin

Chris said:
Hi,

just a dumb question.

Let a = [1,2,3,4,5]

Why is the value of a.append(7) equal None and not [1,2,3,4,5,6,7] ??
I'll assume the presence of the 6 is a typo.

Sorry, that's the case.
Because .append() mutates 'a' and appends the item in-place rather
than creating and returning a new list with the item appended, and
it's good Python style for mutating methods to have no return value
(since all functions must have some return value, Python uses None
when the function doesn't explicitly return anything).

Yes, but this is very unconvenient.
If d should reference the list a extended with a single list element
you need at least two lines

a.append(7)
d=a

and not more intuitive d = a.append(7)

--Armin
 
J

John Machin

Yes, but this is very unconvenient.
If d should reference the list a extended with a single list element
you need at least two lines

a.append(7)
d=a

and not more intuitive d = a.append(7)

Methods/functions which return a value other than the formal None and
also mutate their environment are "a snare and a delusion". Don't wish
for them.

Inconvenient? How often do you want to mutate a list and then set up
another reference to it?
 
C

Chris Rebert

Chris said:
Hi,

just a dumb question.

Let a = [1,2,3,4,5]

Why is the value of a.append(7) equal None and not [1,2,3,4,5,6,7] ??

I'll assume the presence of the 6 is a typo.

Sorry, that's the case.
Because .append() mutates 'a' and appends the item in-place rather
than creating and returning a new list with the item appended, and
it's good Python style for mutating methods to have no return value
(since all functions must have some return value, Python uses None
when the function doesn't explicitly return anything).

Yes, but this is very unconvenient.
If d should reference the list a extended with a single list element
you need at least two lines

a.append(7)
d=a

and not more intuitive d = a.append(7)

And then they'd both reference the same list and you'd run into all
sorts of problems.

The code you'd actually want is:

d = a[:] #copy a
d.append(7)

Or if you're willing to overlook the inefficiency:

d = a + [7]

But that's not idiomatic.

And debating the fundamentals of the language, which aren't going to
change anytime soon, isn't going to get you anywhere.
You may be interested in looking at Python's "tuple" datatype, which
is basically an immutable list.

I'd also suggest you Read The Fine Tutorial, and that your original
question was better suited to IRC or python-tutors
(http://mail.python.org/mailman/listinfo/tutor) than this mailinglist.

Regards,
Chris
 
J

Jerry Hill

Yes, but this is very unconvenient.
If d should reference the list a extended with a single list element
you need at least two lines

You do it in two lines, because you're doing two different things.
a.append(7)

This appends the element 7 to the list a.

This binds the name d to the same list as a is bound to. If you wand
d to point to a new list with the same contents as the list a, plus
the number 7 do this:

d = a + [7]

Here's an example of the difference:
a = range(6)
a [0, 1, 2, 3, 4, 5]
a.append(7)
a [0, 1, 2, 3, 4, 5, 7]
d = a
d [0, 1, 2, 3, 4, 5, 7]
d.append(10)
a [0, 1, 2, 3, 4, 5, 7, 10]
d [0, 1, 2, 3, 4, 5, 7, 10]

See how a and d are two names bound to the same list?

Here's the other way:
a = range(6)
d = a + [7]
a [0, 1, 2, 3, 4, 5]
d [0, 1, 2, 3, 4, 5, 7]
d.append(10)
a [0, 1, 2, 3, 4, 5]
d [0, 1, 2, 3, 4, 5, 7, 10]
 
S

Steven D'Aprano

The code you'd actually want is:

d = a[:] #copy a
d.append(7)

Or if you're willing to overlook the inefficiency:

d = a + [7]

But that's not idiomatic.

Why is a + [7] more inefficient than manually copying the list and
appending to the copy? Surely both pieces of code end up doing the same
thing?

In fact, I'd guess that the second is likely to be marginally more
efficient than the first:

x = compile('d = a[:]; d.append(7)', '', 'exec')
dis.dis(x)
1 0 LOAD_NAME 0 (a)
3 SLICE+0
4 STORE_NAME 1 (d)
7 LOAD_NAME 1 (d)
10 LOAD_ATTR 2 (append)
13 LOAD_CONST 0 (7)
16 CALL_FUNCTION 1
19 POP_TOP
20 LOAD_CONST 1 (None)
23 RETURN_VALUE
x = compile('d = a + [7]', '', 'exec')
dis.dis(x)
1 0 LOAD_NAME 0 (a)
3 LOAD_CONST 0 (7)
6 BUILD_LIST 1
9 BINARY_ADD
10 STORE_NAME 1 (d)
13 LOAD_CONST 1 (None)
16 RETURN_VALUE


timeit agrees with me:
from timeit import Timer
t1 = Timer('d = a[:]; d.append(7)', 'a = []')
t2 = Timer('d = a + [7]', 'a = []')
t1.repeat(number=1000) [0.0015339851379394531, 0.0014910697937011719, 0.0014841556549072266]
t2.repeat(number=1000)
[0.0011889934539794922, 0.0013048648834228516, 0.0013070106506347656]
 
C

Chris Rebert

The code you'd actually want is:

d = a[:] #copy a
d.append(7)

Or if you're willing to overlook the inefficiency:

d = a + [7]

But that's not idiomatic.

Why is a + [7] more inefficient than manually copying the list and
appending to the copy? Surely both pieces of code end up doing the same
thing?

In fact, I'd guess that the second is likely to be marginally more
efficient than the first:

x = compile('d = a[:]; d.append(7)', '', 'exec')
dis.dis(x)
1 0 LOAD_NAME 0 (a)
3 SLICE+0
4 STORE_NAME 1 (d)
7 LOAD_NAME 1 (d)
10 LOAD_ATTR 2 (append)
13 LOAD_CONST 0 (7)
16 CALL_FUNCTION 1
19 POP_TOP
20 LOAD_CONST 1 (None)
23 RETURN_VALUE
x = compile('d = a + [7]', '', 'exec')
dis.dis(x)
1 0 LOAD_NAME 0 (a)
3 LOAD_CONST 0 (7)
6 BUILD_LIST 1
9 BINARY_ADD
10 STORE_NAME 1 (d)
13 LOAD_CONST 1 (None)
16 RETURN_VALUE


timeit agrees with me:
from timeit import Timer
t1 = Timer('d = a[:]; d.append(7)', 'a = []')
t2 = Timer('d = a + [7]', 'a = []')
t1.repeat(number=1000) [0.0015339851379394531, 0.0014910697937011719, 0.0014841556549072266]
t2.repeat(number=1000)
[0.0011889934539794922, 0.0013048648834228516, 0.0013070106506347656]

Sorry, I was just speculating based on the extraneous list ([7]) used
in the second one.
My bad. :)

Regards,
Chris
 
C

Chris Rebert

John said:
Methods/functions which return a value other than the formal None and
also mutate their environment are "a snare and a delusion". Don't wish
for them.



c = [9,10]
[1,2,3,4,7].append(c) -> Is this a valid expression?

Literally, no, because you can't call methods on literals.
However, the sentiment is valid, though probably not what you want:
c = [9,10]
a = [1,2,3,4,7]
b = a[:]
a.append(c)
a #note the nested list [1, 2, 3, 4, 7, [9, 10]]
b [1, 2, 3, 4, 7]
b.extend(c)
b
[1, 2, 3, 4, 7, 9, 10]

Regards,
Chris
 
A

Armin

John said:
Methods/functions which return a value other than the formal None and
also mutate their environment are "a snare and a delusion". Don't wish
for them.



c = [9,10]
[1,2,3,4,7].append(c) -> Is this a valid expression?

The 'value' of that expression is None.

However ... that's the way of the implementation of the append method.
It's a little bit confusing to me ...

--Armin

Thanks to all !
 
A

Alex Marandon

Armin said:
Chris said:
Hi,

just a dumb question.

Let a = [1,2,3,4,5]

Why is the value of a.append(7) equal None and not [1,2,3,4,5,6,7] ??

Because .append() mutates 'a' and appends the item in-place rather
than creating and returning a new list with the item appended, and
it's good Python style for mutating methods to have no return value
(since all functions must have some return value, Python uses None
when the function doesn't explicitly return anything).

Yes, but this is very unconvenient.

Hi,

You might be interested in using the + operator instead of append. You
could also define your own list type, based on the UserList included in
the standard library.
.... def my_append(self, value):
.... return self + [value]
....
>>> l = MyList([1,2,3,4])
>>> l [1, 2, 3, 4]
>>> l.my_append(5) [1, 2, 3, 4, 5]
>>> l
[1, 2, 3, 4]
 
A

Armin

Duncan said:
Chris Rebert said:
[1,2,3,4,7].append(c) -> Is this a valid expression?
Literally, no, because you can't call methods on literals.

Rubbish. There is no restriction about calling methods on literals. That
expression is perfectly valid but has no practical use that I can see.

The semantic of [1,2,3,4,7].append(c) and [1,2,3,4,7] + c
(with c = [8,9]) is identical, but the first expression doesn't provide
a value. Strange by design ...

--Armin

There is a syntax gotcha which you may have been thinking of: to call a
method on an integer literal (or indeed to access any attribute) you have
to use whitespace between the literal and the dot otherwise you have a
float literal and a syntax error.
'0x5'

The only relatively common use I can think of where you might want to call
a method directly on a literal is to produce a list of strings while being
lazy about the typing:

COLOURS = "red green blue pink yellow".split()

versus

COLOURS = ["red", "green", "blue", "pink", "yellow"]
 
A

Alex Marandon

Armin said:
Duncan Booth wrote:

The semantic of [1,2,3,4,7].append(c) and [1,2,3,4,7] + c
(with c = [8,9]) is identical,

No it's not, + doesn't alter its operands.
1

Were you expecting a == 3?
 
A

Armin

Alex said:
Armin said:
Duncan Booth wrote:

The semantic of [1,2,3,4,7].append(c) and [1,2,3,4,7] + c
(with c = [8,9]) is identical,

No it's not, + doesn't alter its operands.
3

That's not the point :)

What's the value of 1.add(b)? None? Or 3 ??
(if add works in the same way as append)
a + b doesn't change a,b ... but a.add(b) -> a=3
 

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,774
Messages
2,569,596
Members
45,139
Latest member
JamaalCald
Top