[Tutor] Standard way to append to a list?
Magnus Lyckå
magnus@thinkware.se
Wed Apr 16 19:02:02 2003
At Tue, 15 Apr 2003 01:44:38 -0400, Brian Christopher Robinson wrote:
>Say I have:
>
>list = [1, 2, 3]
>
>What is the standard way to add 4 to the end of the list? I know:
>
>list = list + [4]
>
>would work. What else is there?
You said it yourself in the subject line. Please read
http://www.python.org/doc/current/lib/typesseq-mutable.html
etc.
First of all, don't use list as a variable name. It's
allowed, but bad practice to use builtin type names as
varible names. See below:
>>> l = list((1,32,5))
>>> l
[1, 32, 5]
>>> list = [1,2,3]
>>> l = list((1,32,5))
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
TypeError: 'list' object is not callable
:( Since you have reassigned the name list to refer to a
particular list object. instead of the list type, you cqan
no longer cast tuples to lists... (Well, you can type
"__builtins__.list((1,32,5))", but that seems a bit
awkward...)
Secondly, using "l = l + [4]" or the shorter form "l += [4]",
you are doing the following:
1. To start with, you have a list object containing [1,2,3]
2. Then you create a new list object containing [4].
3. With your assignment you create a new list object, and
place the sum of the two lists, i.e. [1,2,3,4] in that.
4. As you rebind the variable name "l" from the list
containing [1,2,3] to the one containing [1,2,3,4], you
will reduce the reference count on the list containing
[1,2,3]. If no other variables etc references that list,
it will be garbage collected now (or perhaps a little
later if you are running Jython.)
5. The list containing [4] will also be garbage collected as
soon as the assignment is done.
All this juggling with objects take space and time.
Using "l.append(4)" you will just mutate the already existing
list object, and append is very fast. Lets test it with the
profiler:
>>> import profile
>>> def add():
... l = []
... for i in xrange(10000):
... l = l + [i]
...
>>> profile.run('add()')
3 function calls in 4.799 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 4.664 4.664 4.664 4.664 <interactive input>:1(add)
1 0.002 0.002 4.666 4.666 <string>:1(?)
1 0.133 0.133 4.799 4.799 profile:0(add())
0 0.000 0.000 profile:0(profiler)
>>> def add():
... l = []
... for i in xrange(10000):
... l.append(i)
...
>>> profile.run('add()')
3 function calls in 0.023 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.022 0.022 0.022 0.022 <interactive input>:1(add)
1 0.001 0.001 0.023 0.023 <string>:1(?)
1 0.000 0.000 0.023 0.023 profile:0(add())
0 0.000 0.000 profile:0(profiler)
It seems append is more than 200 times faster in this case. With a
shorter list, I'm sure the difference will be smaller though. Adding
(+) large lists is much slower than appending to large lists.
>>> def add():
... for i in xrange(1000):
... l = []
... for j in range(10):
... l = l + [j]
...
>>> profile.run('add()')
3 function calls in 0.041 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.040 0.040 0.040 0.040 <interactive input>:1(add)
1 0.000 0.000 0.040 0.040 <string>:1(?)
1 0.000 0.000 0.041 0.041 profile:0(add())
0 0.000 0.000 profile:0(profiler)
>>> def add():
... for i in xrange(1000):
... l = []
... for j in range(10):
... l.append(j)
...
>>>
>>> profile.run('add()')
3 function calls in 0.025 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.025 0.025 0.025 0.025 <interactive input>:1(add)
1 0.000 0.000 0.025 0.025 <string>:1(?)
1 0.000 0.000 0.025 0.025 profile:0(add())
0 0.000 0.000 profile:0(profiler)
Now "l = l + [j]" only takes 60% more time, but append is still a better
choice.