which is more pythonic/faster append or +=[]

A

alf

two ways of achieving the same effect


l+=[n]

or

l.append(n)


so which is more pythonic/faster?
 
A

Alex Martelli

alf said:
two ways of achieving the same effect


l+=[n]

or

l.append(n)


so which is more pythonic/faster?

..append - easy to measure, too:

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x.append(n)'
1000000 loops, best of 3: 1.31 usec per loop

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x+=[n]'
1000000 loops, best of 3: 1.52 usec per loop


Alex
 
7

7stud

alf said:
two ways of achieving the same effect
l.append(n)

so which is more pythonic/faster?

.append - easy to measure, too:

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x.append(n)'
1000000 loops, best of 3: 1.31 usec per loop

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x+=[n]'
1000000 loops, best of 3: 1.52 usec per loop

Alex

Why is it necessary to copy L?
 
7

7stud

alf said:
two ways of achieving the same effect
l.append(n)

so which is more pythonic/faster?

.append - easy to measure, too:

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x.append(n)'
1000000 loops, best of 3: 1.31 usec per loop

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x+=[n]'
1000000 loops, best of 3: 1.52 usec per loop

Alex

Ah, I see. The list would grow too large with all that appending, so
you begin again with the original list for every loop.

Is there any documentation for the syntax you are used with timeit? I
checked 'man python', and I also read the example in the python docs,
but you seem to be using a hybrid syntax.

Thanks.
 
K

kyosohma

alf said:
two ways of achieving the same effect
l+=[n]
or
l.append(n)
so which is more pythonic/faster?
.append - easy to measure, too:
brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x.append(n)'
1000000 loops, best of 3: 1.31 usec per loop
brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x+=[n]'
1000000 loops, best of 3: 1.52 usec per loop

Ah, I see. The list would grow too large with all that appending, so
you begin again with the original list for every loop.

Is there any documentation for the syntax you are used with timeit? I
checked 'man python', and I also read the example in the python docs,
but you seem to be using a hybrid syntax.

Thanks.

If you want to have multiple statements on one line, all you need to
do is add the semi-colon. That is what Alex did. I think I saw that
trick in the book "Programming Python" by Lutz...or some other
reference text. Here's one link to the anomaly:
http://safari.oreilly.com/0201748843/ch07lev1sec5

Here's another link that mentions it as well:
http://www-128.ibm.com/developerworks/opensource/library/os-python5/

Mike
 
A

Alex Martelli

7stud said:
.append - easy to measure, too:

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x.append(n)'
1000000 loops, best of 3: 1.31 usec per loop

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x+=[n]'
1000000 loops, best of 3: 1.52 usec per loop

Alex

Why is it necessary to copy L?

If you don't, then L gets longer and longer -- to over a million
elements by the end of the loop -- so we're measuring something that's
potentially very different from the problem under study, "what's the
best way to append one item to a 3-items list".

That's important to consider for any microbenchmark of code that changes
some existing state: make sure you're measuring a piece of code that
_overall_ does NOT change said existing state in a cumulative way,
otherwise you may be measuring something very different from the issue
of interest. It's maybe the only important caveat about using "python
-mtimeit".


Alex
 
S

Stargaming

Alex said:
.append - easy to measure, too:

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x.append(n)'
1000000 loops, best of 3: 1.31 usec per loop

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x+=[n]'
1000000 loops, best of 3: 1.52 usec per loop

Alex

Why is it necessary to copy L?


If you don't, then L gets longer and longer -- to over a million
elements by the end of the loop -- so we're measuring something that's
potentially very different from the problem under study, "what's the
best way to append one item to a 3-items list".

That's important to consider for any microbenchmark of code that changes
some existing state: make sure you're measuring a piece of code that
_overall_ does NOT change said existing state in a cumulative way,
otherwise you may be measuring something very different from the issue
of interest. It's maybe the only important caveat about using "python
-mtimeit".


Alex

Cannot reproduce that. Consider the following:

$ python -mtimeit "L=range(3)" "L.append(1); print len(L)"
4
4
[...]
4
1000 loops, best of 3: [...]

Doesn't seem like copying is really neccessary.
 
P

Peter Otten

Stargaming said:
Alex said:
.append - easy to measure, too:

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x.append(n)'
1000000 loops, best of 3: 1.31 usec per loop

brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x+=[n]'
1000000 loops, best of 3: 1.52 usec per loop

Alex

Why is it necessary to copy L?


If you don't, then L gets longer and longer -- to over a million
elements by the end of the loop -- so we're measuring something that's
potentially very different from the problem under study, "what's the
best way to append one item to a 3-items list".

That's important to consider for any microbenchmark of code that changes
some existing state: make sure you're measuring a piece of code that
_overall_ does NOT change said existing state in a cumulative way,
otherwise you may be measuring something very different from the issue
of interest. It's maybe the only important caveat about using "python
-mtimeit".


Alex

Cannot reproduce that. Consider the following:

$ python -mtimeit "L=range(3)" "L.append(1); print len(L)"

That should be

$ python2.5 -m timeit -s "L = range(3)" "L.append(1); print len(L)" | tail
999995
999996
999997
999998
999999
1000000
1000001
1000002
1000003
1000000 loops, best of 3: 1.98 usec per loop

Note the -s before the initialization statement that Alex meant to add but
didn't. If that is missing

L = range(3)

is executed on every iteration.

Peter
 
7

7stud

Is there any documentation for the syntax you used with timeit?

This is the syntax the docs describe:
---
Python Reference Library
10.10.1:

When called as a program from the command line, the following form is
used:

python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
---

Then in the examples in section 10.10.2, the docs use a different
syntax:

----
% timeit.py 'try:' ' str.__nonzero__' 'except AttributeError:' '
pass'
100000 loops, best of 3: 15.7 usec per loop
% timeit.py 'if hasattr(str, "__nonzero__"): pass'
100000 loops, best of 3: 4.26 usec per loop
% timeit.py 'try:' ' int.__nonzero__' 'except AttributeError:' '
pass'
1000000 loops, best of 3: 1.43 usec per loop
% timeit.py 'if hasattr(int, "__nonzero__"): pass'
100000 loops, best of 3: 2.23 usec per loop
---

and then there is Alex Martelli's syntax:
brain:~ alex$ python -mtimeit 'L=range(3); n=23' 'x=L[:]; x.append(n)'
 
S

Steven Bethard

7stud said:
Is there any documentation for the syntax you used with timeit?

This is the syntax the docs describe: [snip
python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...] [snip]
Then in the examples in section 10.10.2 [snip]
timeit.py 'try:' ' str.__nonzero__' 'except AttributeError:' ' pass' [snip]
and then there is Alex Martelli's syntax: [snip]
python -mtimeit 'L=range(3); n=23' 'x=L[:]; x.append(n)'

The following three things are equivalent:
python /path/to/<module>.py
/path/to/<module>.py # assuming the OS knows how to exec it
python -m<module> # assuming <module> is on sys.path

So that just leaves the differences between:
[-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
'try:' ' str.__nonzero__' 'except AttributeError:' ' pass'
'L=range(3); n=23' 'x=L[:]; x.append(n)'

Those look pretty similar to me (aside from the fact that they're
testing different things). Each argument in single quotes is a line of
the code you want timed.

HTH,

STeVe
 
A

Alex Martelli

Peter Otten said:
Note the -s before the initialization statement that Alex meant to add but
didn't. If that is missing

Yep, sorry for erroneously skipping the -s!


Alex
 
7

7stud

7studwrote:
This is the syntax the docs describe: [snip
python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...] [snip]
Then in the examples in section 10.10.2 [snip]
timeit.py 'try:' ' str.__nonzero__' 'except AttributeError:' ' pass' [snip]
and then there is Alex Martelli's syntax: [snip]
python -mtimeit 'L=range(3); n=23' 'x=L[:]; x.append(n)'

The following three things are equivalent:
python /path/to/<module>.py
/path/to/<module>.py # assuming the OS knows how to exec it
python -m<module> # assuming <module> is on sys.path

So that just leaves the differences between:
[-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...]
'try:' ' str.__nonzero__' 'except AttributeError:' ' pass'
'L=range(3); n=23' 'x=L[:]; x.append(n)'

Those look pretty similar to me (aside from the fact that they're
testing different things). Each argument in single quotes is a line of
the code you want timed.

Thanks.
 

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,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top