Python append() vs. + operator on lists, why do these give different results?
To explain "why":
The +
operation adds the array elements to the original array. The array.append
operation inserts the array (or any object) into the end of the original array, which results in a reference to self in that spot (hence the infinite recursion in your case with lists, though with arrays, you'd receive a type error).
The difference here is that the +
operation acts specific when you add an array (it's overloaded like others, see this chapter on sequences) by concatenating the element. The append
-method however does literally what you ask: append the object on the right-hand side that you give it (the array or any other object), instead of taking its elements.
An alternative
Use extend()
if you want to use a function that acts similar to the +
operator (as others have shown here as well). It's not wise to do the opposite: to try to mimic append
with the +
operator for lists (see my earlier link on why). More on lists below:
Lists
[edit] Several commenters have suggested that the question is about lists and not about arrays. The question has changed, though I should've included this earlier.
Most of the above about array
s also applies to lists:
- The
+
operator concatenates two lists together. The operator will return a new list object. List.append
does not append one list with another, but appends a single object (which here is alist
) at the end of your current list. Addingc
to itself, therefore, leads to infinite recursion.- As with arrays, you can use
List.extend
to add extend a list with another list (oriterable
). This will change your current list in situ, as opposed to+
, which returns a new list.
Little history
For fun, a little history: the birth of the array module in Python in February 1993. it might surprise you, but arrays were added way after sequences and lists came into existence.
In Python, what is the difference between .append() and += [] ?
For your case the only difference is performance: append is twice as fast.
Python 3.0 (r30:67507, Dec 3 2008, 20:14:27) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.Timer('s.append("something")', 's = []').timeit()
0.20177424499999999
>>> timeit.Timer('s += ["something"]', 's = []').timeit()
0.41192320500000079
Python 2.5.1 (r251:54863, Apr 18 2007, 08:51:08) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import timeit
>>> timeit.Timer('s.append("something")', 's = []').timeit()
0.23079359499999999
>>> timeit.Timer('s += ["something"]', 's = []').timeit()
0.44208112500000141
In general case append
will add one item to the list, while +=
will copy all elements of right-hand-side list into the left-hand-side list.
Update: perf analysis
Comparing bytecodes we can assume that append
version wastes cycles in LOAD_ATTR
+ CALL_FUNCTION
, and += version -- in BUILD_LIST
. Apparently BUILD_LIST
outweighs LOAD_ATTR
+ CALL_FUNCTION
.
>>> import dis
>>> dis.dis(compile("s = []; s.append('spam')", '', 'exec'))
1 0 BUILD_LIST 0
3 STORE_NAME 0 (s)
6 LOAD_NAME 0 (s)
9 LOAD_ATTR 1 (append)
12 LOAD_CONST 0 ('spam')
15 CALL_FUNCTION 1
18 POP_TOP
19 LOAD_CONST 1 (None)
22 RETURN_VALUE
>>> dis.dis(compile("s = []; s += ['spam']", '', 'exec'))
1 0 BUILD_LIST 0
3 STORE_NAME 0 (s)
6 LOAD_NAME 0 (s)
9 LOAD_CONST 0 ('spam')
12 BUILD_LIST 1
15 INPLACE_ADD
16 STORE_NAME 0 (s)
19 LOAD_CONST 1 (None)
22 RETURN_VALUE
We can improve performance even more by removing LOAD_ATTR
overhead:
>>> timeit.Timer('a("something")', 's = []; a = s.append').timeit()
0.15924410999923566
Is a Python list's += operator equivalent to append() or extend()?
In python += on a list is equivalent to extend
method on that list.
What is the difference between Python's list methods append and extend?
append
appends a specified object at the end of the list:
>>> x = [1, 2, 3]
>>> x.append([4, 5])
>>> print(x)
[1, 2, 3, [4, 5]]
extend
extends the list by appending elements from the specified iterable:
>>> x = [1, 2, 3]
>>> x.extend([4, 5])
>>> print(x)
[1, 2, 3, 4, 5]
Appending to list using append method and + operator produces different results in Python?
the difference is that lst.append(item)
appends an item
to the existing list (in-place) and returns None
while the +
operator (__add__
) returns the result of the concatenation (a new list).
so when you call check( path.append(i), item, slns )
you do modify the list path
but you effectively call check(None , item, slns )
instead of the new list as the first argument.
What is the difference between append and + in python?
The strange behavior you can see with your example is not due to the difference between the + operator and the append function.
It is due to the fact that you assigned a list as a default value to a function parameter and you assign the result of a concatenation in a local variable in g
.
That is not so widely known but defining a list (or a dict or an object) as a parameter default value is probably not what you want. When you do so, the list used as default value for the parameter is shared across all function calls.
So for the f
function:
- you call it a first time without the
L
parameter, the default value ([]
) is taken and appended with2
. So it becomes[2]
- you call it a second time without the
L
parameter, the default value is taken but it is now[2]
.2
is appended again and it becomes[2, 2]
which is now the default value of your function.
for the g
function:
- as for the
f
function, the default value is an empty list, but this list is never modified. Actually the result ofL + [2]
is affected to a local variableL
and the default value of the function remains unchanged. So when you call the function again, the default value is always[]
. - As Klimenkomud said in his answer using the
+=
operator instead of a concatenation and an assignation actually modifies the default value of theL
parameter. If you do so, theg
function will behave like thef
function.
As a conclusion, using an empty list as a parameter default value is almost never what you want. Instead, you probably want this:
def f(a, L=None):
L = L or []
...
Why do these two append methods produce different results?
Function second_append
always creates a new local list for you each time it is called.
Why does not the + operator change a list while .append() does?
So in a function the adding a 6 to the set doesn't show but it does when not in a function?
No, that is not what happens.
What happens is that, when you execute mylist = mylist + [6]
, you are effectively creating an entirely new list and putting it in the local mylist
variable. This mylist
variable will vanish after the execution of the function and the newly created list will vanish as well.
OTOH when you execute mylist.append(6)
you do not create a new list. You get the list already in the mylist
variable and add a new element to this same list. The result is that the list (which is pointed by list2
too) will be altered itself. The mylist
variable will vanish again, but in tis case you altered the original list.
Let us see if a more visual explanation can help you :)
What happens when you call proc()
When you write list1 = [1, 2, 3, 4, 5]
you are creating a new list object (at the right side of the equals sign) and creating a new variable, list1
, which will point to this object.
Then, when you call proc()
, you create another new variable, mylist
, and since you pass list1
as parameter, mylist
will point to the same object:
However, the operation mylist + [6]
creates a whole new list object whose contents are the contents of the object pointed by mylist
plus the content of the following list object - that is, [6]
. Since you attribute this new object to mylist
, our scenario changes a bit and mylist
does not point to the same object pointed by list1
anymore:
What I have not said is that mylist
is a local variable: it will disappear after the end of the proc()
function. So, when the proc()
execution ended, the mylist
is gone:
Since no other variable points to the object generated by mylist + [6]
, it will disappear, too (since the garbage collector* will collect it):
Note that, in the end, the object pointed by list1
is not changed.
What happens when you call proc2()
Everything changes when you call proc2()
. At first, it is the same thing: you create a list...
...and pass it as a parameter to a function, which will generate a local variable:
However, instead of using the +
concatenation operator, which generates a new list, you apply the append()
method to the existing list. The append()
method does not create a new object; instead, it _changes the existing one:
After the end of the function, the local variable will disappear, but the original object pointed by it and by list1
will be already altered:
Since it is still pointed by list1
, the original list is not destroyed.
EDIT: if you want to take a look at all this stuff happening before your eyes just go to this radically amazing simulator:
* If you do not know what is garbage collector... well, you will discover soon after understanding your own question.
Related Topics
Dictionary Creation with Fromkeys and Mutable Objects. a Surprise
Change One Value Based on Another Value in Pandas
Strings in a Dataframe, But Dtype Is Object
Best Practice for Using Assert
How to Convert a String of Bytes into an Int
Checking Whether a String Starts with Xxxx
Differencebetween a Function, an Unbound Method and a Bound Method
How to Escape Os.System() Calls
Store Different Datatypes in One Numpy Array
Fixed Digits After Decimal with F-Strings
How to Access Command Line Arguments