Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between "append" and "+" in python? [duplicate]

Tags:

python

I don't know what is difference between f() and g().

In function f, list L is accumulated whenever function is called..

but in function g, it does not..

def f(a, L=[]):
    L.append([2]);
    print(L);

def g(a, L=[]):
    L = L+[2];
    print(L);

print("f:")
f(1) # [[2]]
f(2) # [[2], [2]]
f(3) # [[2], [2], [2]]

print("g:")
g(1) # [2]
g(2) # [2]
g(3) # [2]
like image 728
hs p Avatar asked Aug 10 '18 07:08

hs p


5 Answers

In first function you update existing list, when you append to the end of list new values.

In second function, you just reassign value to list, which means that you didn't add values that list, but just, lets say, recreate it with same value each time function called.

In both cases, you create local variable for function, which appended to that function clouser. So, in both cases you have local variable, which live in function scope. When you run your function 1-st time, in case of default value of variable, it will be memorized, and later, in case of executing function again, it will not be reinitialized by function, but would be taken from function scope.

For example, try to update code of g function to next one:

def g(a, L=[]):
    L += [2]
    print(L)

There you will see, that L accumulated too, as in f function, because here you not reassign the value, but update existing variable.

like image 130
Klimenko Kirill Avatar answered Oct 15 '22 19:10

Klimenko Kirill


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:

  1. you call it a first time without the L parameter, the default value ([]) is taken and appended with 2. So it becomes [2]
  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 of L + [2] is affected to a local variable L 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 the L parameter. If you do so, the g function will behave like the f 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 []
    ...
like image 32
Tryph Avatar answered Oct 15 '22 17:10

Tryph


Append adds the element to the end of the list. So if the list initially is L=[], then L.append([2]) will append a single element list to the original list L. If you again do L.append([3]), it will append another single element list to the end of original list L. Your list L is now actually list of lists.

+ is the concatenation operator. It joins two lists just like it joins two strings. Also, keep in mind that the + operator will always return a new list with elements joined. This is the reason why your list does not grow when you use the + operator. If you just want to mutate the existing list, you can use the extend function. The following answer and comments will make it more clear to you:

Difference between append vs. extend list methods in Python

Hope that helps.

Edit: To show how + returns a new list every time, here is the modified code that prints the id of the list everytime it prints the list:

def f(a, L=[]):
    L.append([2]);
    print(L);
    print(id(L))

def g(a, L=[]):
    #The following statement will print the id of default L
    print(id(L))
    L = L+[2];
    #The following statement will print the id of a new L stored in a diff location. The default L isnt modified.
    print(L);
    print(id(L))

f:
[[2]]
2354851792712
[[2], [2]]
2354851792712
[[2], [2], [2]]
2354851792712
g:
2354851792968
[2]
2354851791944
2354851792968
[2]
2354851791816
2354851792968
[2]
2354851792328

As you see above, every time you append, you use the same default list(2354851792712). Hence your list grows. On the other hand, using the + returns a new list and stores it in a new location, instead of modifying the default L location(2354851792968). Hence, it does not grow.

like image 29
Chaitanya Bangera Avatar answered Oct 15 '22 17:10

Chaitanya Bangera


list.append(element)

adds the "element" to the list. It doesn't discriminate based on data type of the "element".

The concatenation operator '+' although seems to perform the same operation, it concatenates only the same data types. Thus, you can concatenate only lists to lists. You can't have list1+"string". But you can have list1+["string1"], list1.append("string1") and list1.append(["string1"]).

Contrary to common belief, in python, lists are not immutable (mutable). That means, the same object can be edited over and over again without changing its reference. However, tuples and strings are immutable. That means, a new object is created whenever you edit a tuple or a string. The old string/tuple is then discarded by the garbage collection system.

like image 26
Nirmal Avatar answered Oct 15 '22 18:10

Nirmal


You are using a mutable default value. The first time you call f() or g() the interpreter creates an persistent list. With append in f() you are modifying this list. The + operator in g()causes the creation of a new list object, therefore the persistent list object created for the default value remains untouched. Use id(L) to print the reference to the objects to get a deeper insight.

Using mutable default values is considered an anti-pattern, since they can cause exactly this unexpected behavior (Source).

Update

Try running this code and you will see that L has a new id after assigning the result of the + operation and does not "point" to the persistent default value object anymore (it stayed unmodified).

def a(new_element, L=[]):
    print(id(L))
    L = L + [new_element]
    print(id(L))

a(1)
like image 28
Stefan Scheller Avatar answered Oct 15 '22 18:10

Stefan Scheller