Lists 3 - Basic methods

Download exercises zip

Browse files online

Lists are objects of type list and have several methods for performing operations on them, let’s see the basic ones:

Method

Returns

Description

list.append(obj)

None

Adds a new element at the end of the list

list1.extend(list2)

None

Adds many elements at the end of the list

list.insert(int,obj)

None

Adds a new element into some given position

list.pop()

obj

Removes and return the element at last position

list.pop(int)

obj

Given an index, removes and return the element at that position

list.reverse()

None

Inverts the order of elements

list.sort()

None

Sorts the elements in-place

“sep”.join(seq)

string

produces a string concatenating all the elements in seq separated by "sep"

list.copy()

list

Copia superficialmente la list

The others are described at the page Search methods

WARNING 1: LIST METHODS *MODIFY* THE LIST ON WHICH ARE CALLED !

Whenever you call a method of a list (the object to the left of the dot .), you MODIFY the list itself (differently from string methods which always generate a new string without changing the original)

WARNING 2: LIST METHODS RETURN NOTHING!

They almost always return the object None (differently from strings which always return a new string)

What to do

  1. Unzip exercises zip in a folder, you should obtain something like this:

lists
    lists1.ipynb
    lists1-sol.ipynb
    lists2.ipynb
    lists2-sol.ipynb
    lists3.ipynb
    lists3-sol.ipynb
    lists4.ipynb
    lists4-sol.ipynb
    lists5-chal.ipynb
    jupman.py

WARNING: to correctly visualize the notebook, it MUST be in an unzipped folder !

  1. open Jupyter Notebook from that folder. Two things should open, first a console and then a browser. The browser should show a file list: navigate the list and open the notebook lists3.ipynb

  2. Go on reading the exercises file, sometimes you will find paragraphs marked Exercises which will ask to write Python commands in the following cells.

Shortcut keys:

  • to execute Python code inside a Jupyter cell, press Control + Enter

  • to execute Python code inside a Jupyter cell AND select next cell, press Shift + Enter

  • to execute Python code inside a Jupyter cell AND a create a new cell aftwerwards, press Alt + Enter

  • If the notebooks look stuck, try to select Kernel -> Restart

append method

We can MODIFY a list adding a single element at a time with the method append.

Suppose to start from an empty list:

[2]:
la = []

If we want to add as element the number 50, we can write like this:

[3]:
la.append(50)

Note the list we initalilly created got MODIFIED:

[4]:
la
[4]:
[50]

WARNING: la.append(50) returned NOTHING !!!!

Observe carefully the output of cell with instruction la.append(50), you will notice there is absolutely nothing. This happens because the purpose of append is to MODIFY the list on which it is called, NOT generating new lists.

We append another number at the end of the list:

[5]:
la.append(90)
[6]:
la
[6]:
[50, 90]
[7]:
la.append(70)
[8]:
la
[8]:
[50, 90, 70]

Let’s see what happened in Python Tutor:

[9]:
# WARNING: FOR PYTHON TUTOR TO WORK, REMEMBER TO EXECUTE THIS CELL with Shift+Enter
#          (it's sufficient to execute it only once)

import jupman
[10]:
la = []
la.append(50)
la.append(90)
la.append(70)

jupman.pytut()
[10]:
Python Tutor visualization

Note there is only one yellow memory region associated to variable la which gets expanded as you click on Next.

We said append method returns nothing, let’s try to add some detail. In the methods table, there is present a column named Returns. If you check it, for almost all methods included append there is indicated it returns None.

None is the most boring object in Python, because it literally means nothing. What can you do with nothing? Very few things, so few that whenever Jupyter finds as result the None object it doesn’t even print it. Try directly inserting None in a cell, you will see it won’t be reported in cell output:

[11]:
None

A way to force the print is by using the command print:

[12]:
print(None)
None

EXERCISE: What is the type of the object None? Discover it by using the funciton type

Show solution
[13]:

# write here

Let’s try repeating what happens with append. If you call the method append on a list, append silently MODIFIES the list, and RETURNS the object None as call result. Notice that Jupyter considers this object as non-interesting, so it doesn’t even print it.

Let’s try to get explicit about this misterious None. If it’s true that append produces it as call result, it means we can associate this result to some variable. Let’s try to associate it to variable x:

[14]:
la = []
x = la.append(70)

Now, if everything went as we wrote, append should have modified the list:

[15]:
la
[15]:
[70]

and there should be associated None to variable x. So, if we ask Jupyter to show the value associated to x and that value is None, nothing will appear:

[16]:
x

Note there is no output in the cell, apparently we are really in presence of a None. Let’s force the print:

[17]:
print(x)
None

Here it is! Probably you will be a little confused by all of this, so let’s check again what happens in Python Tutor:

[18]:
la = []
x = la.append(70)
print("la is", la)
print("x is", x)

jupman.pytut()
la is [70]
x is None
[18]:
Python Tutor visualization

What’s the final gist?

REUSING THE RESULT OF LIST METHODS CALLS IS ALMOST ALWAYS AN ERROR !

Since calling list methods returns None, which is a ‘useless’ object, trying to reuse it will almost surely produce an error

EXERCISE: Build a list by adding one element at a time with the method append. Add the elements 77, "test", [60,93] with three calls to append, and finally print the list.

After your code, you should see [77, 'test', [60, 93]]

Show solution
[19]:

la = [] # write here

QUESTION: The following code:

la = []
la.append(80,70,90)
  1. produces an error (which one?)

  2. modifies the list (how?)

Show answer

QUESTION: The following code:

la = []
la.append(80).append(90)
  1. produces an error

  2. appends to la the numbers 80 and 90

Show answer

QUESTION: let’s briefly go back to strings. Look at the following code (if you don’t remember what string methods do see here)

sa = '    trento    '
sb = sa.strip().capitalize()
print(sb)
  1. produces an error (which one?)

  2. changes sa (how?)

  3. prints something (what?)

Show answer

QUESTION: Have a look at this code. Will it print something at the end? Or will it produce an error?

la = []
lb = []
la.append(lb)

lb.append(90)
lb.append(70)

print(la)
Show answer

Exercise - augmenting a list 1

Given the list la of fixed dimension 7, write some code to augment the empty list lb so to only contain the elements of la with even index (0, 2, 4, …).

  • Your code should work with any list la of fixed dimension 7

#   0 1 2 3 4 5 6
la=[8,4,3,5,7,3,5]
lb=[]

After your code, you should obtain:

>>> print(lb)
[8,3,7,5]
Show solution
[20]:

# 0 1 2 3 4 5 6 la=[8,4,3,5,7,3,5] lb=[] # write here

extend method

We’ve seen that with append we can augment a list one element at a time.

What if we wanted to add many elements in a single shot, maybe taken from another list?

We should use the method extend, which MODIFIES the list on which it is called by adding all the elements it finds in the input sequence.

[21]:
la = [70,30,50]
[22]:
lb = [40,90,30,80]
[23]:
la.extend(lb)
[24]:
la
[24]:
[70, 30, 50, 40, 90, 30, 80]
[25]:
lb
[25]:
[40, 90, 30, 80]

In the example above, extend is called on the variable la, and we passed lb as parameter

WARNING: la is MODIFIED, but the sequence we passed in round parenthesis is not (lb in the example)

QUESTION: the execution of method extend returns something? What do you see in the output of cell la.extend(lb) ?

Show answer

Let’s verify what happened with Python Tutor:

[26]:
la = [70,30,50]
lb = [40,90,30,80]
la.extend(lb)

jupman.pytut()
[26]:
Python Tutor visualization

QUESTION: Look inside this code. Which will be the values associated to variables la ,lb and x after its execution?

la = [30,70,50]
lb = [80,40]
x = la.extend(lb)

print('la is ', la)
print('lb is ', lb)
print('x  is ', x)
Show answer

Extending with sequences

We said that extend can take any generic sequence in the round parenthesis, not only lists. This means we can also try to pass a string. For example:

[27]:
la = [70,60,80]

s = "hello"

la.extend(s)
[28]:
la
[28]:
[70, 60, 80, 'h', 'e', 'l', 'l', 'o']

Since the string is a character sequence, extend took each of these elements and added them to la

QUESTION: was the value associated to variable s modified?

Show answer

QUESTION: The following code:

la = [60,50]
la.extend(70,90,80)
  1. produces un error (which one?)

  2. modifies la (how?)

Show answer

QUESTION: If this code is executed, what happens?

sa = "hello"
sb = "world"
sa.extend(sb)
  1. sa is modified (how?)

  2. we get an error (which one?)

Show answer

QUESTION: If this code is executed, what happens?

la = [1,2,3]
lb = [4,5]
lc = [6,7,8]

la.extend(lb).extend(lc)
  1. la becomes [1,2,3,4,5,6,7,8]

  2. an error (which one?)

  3. la becomes [1,2,3,4,5] and an error (which one?)

QUESTION: 3: la becomes [1,2,3,4,5] and right after we get an error, because the call to la.extend(lb) MODIFIES la to [1,2,3,4,5] and RETURN the value None. At that point, Python tries to call the method extend on the object None, but since it is not a list, we get an error (to convince yourself, verify everything with Python Tutor !!!)

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-45-0a08a154ada4> in <module>
      3 lc = [6,7,8]
      4
----> 5 la.extend(lb).extend(lc)

AttributeError: 'NoneType' object has no attribute 'extend'

Exercise: augmenting a list 2

Given two lists la and lb and an element x, write some code to MODIFY la so that la contains at the end the element x followed by all other elements of lb

  • NOTE 1: your code should work with any la and lb

  • NOTE 2: id is a Python function which associates to each memory region a unique identifier. If you try printing id(la) before modyfing la and id(la) afterwards, you should obtain exactly the same id. If you obtain a different one, it means you generated an entirely new list. In that case, verify how it’s working with Python Tutor.

la = [5,9,2,4]
lb = [7,1,3]
x = 8

You should obtain:

>>> print(la)
[5,9,2,4,8,7,1,3]
>>> print(lb)
[7,1,3]
>>> print(x)
8
Show solution
[29]:

la = [5,9,2,4] lb = [7,1,3] x = 8 # write here

Exercise - zslice

Write some code which given two lists la (of at least 3 elements) and lb, MODIFIES lb in such a way to add 3 elements of la followed by the last 3 of la.

  • your code must work with any list

  • use extends and slices

la = ['a','b','c','d','e','f','g','h','i','l','m','n','o']
lb = ['z']

You should obtain:

>>> print(la)
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'l', 'm', 'n', 'o']
>>> print(lb)
['z', 'a', 'b', 'c', 'm', 'n', 'o']
Show solution
[30]:


la = ['a','b','c','d','e','f','g','h','i','l','m','n','o'] lb = ['z'] # write here

Exercise - Zebarerun

Write some code which given a list of three strings words and an empty list la, fills la with all the first 3 characters of every string in words.

  • your code must work with any list of 3 strings

  • use slices

Example given:

words = ["Zebras", "are", "running"]
la = []

Your code must show:

>>> print(t)
['Z', 'e', 'b', 'a', 'r', 'e', 'r', 'u', 'n']
Show solution
[31]:

words = ["Zebras", "are", "running"] la = [] # write here

insert method

insert MODIFIES the list by inserting an element at a specific index - all elements starting from that index will be shifted of one position to the right.

[32]:
     #0 1 2 3
la = [6,7,8,9]
[33]:
la.insert(2,55)  # insert the number 55 at index 2
[34]:
la
[34]:
[6, 7, 55, 8, 9]
[35]:
la.insert(0,77)  # insert the number 77 at index 0
[36]:
la
[36]:
[77, 6, 7, 55, 8, 9]

We can insert after the end:

[37]:
la.insert(6,88)  # insert the number 88 at index 6
[38]:
la
[38]:
[77, 6, 7, 55, 8, 9, 88]

Note that if we go beyond the end, the element is placed right after the end and no empty cells are created:

[39]:
la.insert(1000,99)  # insert number 99 at index 7
[40]:
la
[40]:
[77, 6, 7, 55, 8, 9, 88, 99]

QUESTION: Given any list x, what does this code produce? Can we rewrite it in some other way?

x.insert(len(x),66)
  1. produces a new list (which one?)

  2. modifies x (how?)

  3. an error

Show answer

QUESTION: What does the following code produce?

la = [3,4,5,6]
la.insert(0,[1,2])
print(la)
  1. prints [1,2,3,4,5,6]

  2. an error (which one?)

  3. something else (what?)

Show answer

QUESTION: What does the following code produce?

la = [4,5,6]
la.insert(0,1,2,3)
print(la)
  1. prints [1,2,3,4,5,6]

  2. an error (which one?)

  3. something else (what?)

Show answer

QUESTION: What does the following code produce?

la = [4,5,6]
lb = la.insert(0,3)
lc = lb.insert(0,2)
ld = lc.insert(0,1)
print(ld)
  1. prints [1,2,3,4,5,6]

  2. an error (which one?)

  3. something else (what?)

Show answer

Exercise - insertando

Given the list

la = [7,6,8,5,6]

write some code which MODIFIES the list by using only calls to insert. After your code, la should appear like this:

>>> print(la)
[7, 70, 90, 6, 8, 80, 5, 6, 50]
Show solution
[41]:

la = [7,6,8,5,6] # write here

WARNING: calling insert is much slower than append !!

A call to insert rewrites all the cells after the insertion point, while append instead adds only one cell. Given the computer is fast, very often we don’t realize the difference, but whenever possible try writing code using append instead of insert, especially if you have to write programs which operate on big amounts of data.

Exercise - insappend

This code takes as input an empty list la and a list of numbers lb. Try to understand what it does, and rewrite it using some append.

[42]:
la = []
lb = [7,6,9,8]
la.insert(0,lb[0]*2)
la.insert(0,lb[1]*2)
la.insert(0,lb[2]*2)
la.insert(0,lb[3]*2)
print(la)
[16, 18, 12, 14]
Show solution
[43]:

la = [] lb = [7,6,9,8] # write here

pop method

pop method does two things: when called without arguments MODIFIES the list by removing the last element, and also RETURNS the removed element:

[44]:
basket = ['melon','strawberry', 'apple']
[45]:
basket.pop()
[45]:
'apple'
[46]:
basket
[46]:
['melon', 'strawberry']
[47]:
basket.pop()
[47]:
'strawberry'
[48]:
basket
[48]:
['melon']

Since the last element is returned by pop, we can also assign it to a variable:

[49]:
fruit = basket.pop()

Note we don’t see no result printed because the returned element was assigned to the variable fruit:

[50]:
fruit
[50]:
'melon'

We also notice that basket was MODIFIED indeed:

[51]:
basket
[51]:
[]

If you further call pop on an empty list you will get an error:

basket.pop()
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-67-086f38c9fbc0> in <module>()
----> 1 basket.pop()

IndexError: pop from empty list

Optionally, to remove an element from a specific position we can pass pop an index from 0 INCLUDED to the length of the list EXCLUDED:

[52]:
#           0           1             2        3
tools = ['hammer', 'screwdriver', 'plier', 'hammer']
[53]:
tools.pop(2)
[53]:
'plier'
[54]:
tools
[54]:
['hammer', 'screwdriver', 'hammer']

QUESTION: Have a look at following code snippets, and for each of them try to guess the result it produces (or if it gives an error):

  1. la = ['a']
    print(la.pop())
    print(la.pop())
    
  2. la = [4,3,2,1]
    print(la.pop(4))
    print(la)
    
  3. la = [1,2,3,4]
    print(la.pop(3))
    print(la)
    
  4. la = [1,2,3,4]
    print(la.pop(-1))
    print(la)
    
  5. s = 'raw'
    print(s.pop())
    print(s)
    
  6. la = ['so', 'raw']
    print(la.pop())
    print(la)
    
  7. la = ['a', ['a']]
    print(la.pop())
    print(la)
    

Exercise - popcorn

Given the list corn of exactly 4 characters, write some code which transfers in reverse order all the characters from corn to another list box which is initially empty.

  • DO NOT use methods like reverse or functions like reversed

  • Your code must work with any list corn of 4 elements

Example - given:

corn = ['G','u','r','u']
box = []

after your code, it must result:

>>> print(corn)
[]
>>> print(box)
['u', 'r', 'u', 'G']
Show solution
[55]:

corn = ['G','u','r','u'] box = [] # write here

Exercise - zonzo

Given a list la containing some characters, and a list lb containing exactly two positions in ascending order, write some code which eliminates from la the characters at positions specified in lb.

  • WARNING: by calling pop the first time you will MODIFY la, so the index from the second element to eliminate will need to be properly adjusted !

  • DO NOT create new lists, so no rows beginning with la =

  • Your code must work with any la and any lb of two elements

Example - given:

#      0   1   2   3   4
la = ['z','o','n','z','o']
lb = [2,4]

at position 2 in la we find the n and at 4th the o, so after your code it must result:

>>> print(la)
['z', 'o', 'z']
Show solution
[56]:

# 0 1 2 3 4 la = ['z','o','n','z','o'] lb = [2,4] # write here

reverse method

reverse method MODIFIES the list on which it is called by inverting the order of elements.

Let’s see an example:

[57]:
la = [7,6,8,4]
[58]:
la.reverse()
[59]:
la
[59]:
[4, 8, 6, 7]

WARNING: reverse RETURNS NOTHING!

To be precise, it returns None

[60]:
lb = [7,6,8,4]
[61]:
x = lb.reverse()
[62]:
print(x)
None
[63]:
print(lb)
[4, 8, 6, 7]

QUESTION: Which effect does the following code produce?

s = "transatlantic"
s.reverse()
print(s)
  1. an error (which one?)

  2. prints the string in reverse

Show answer

QUESTION: If x is some list, which effect does the following produce?

x.reverse().reverse()
  1. changes the list (how?)

  2. it doesn’t change the list

  3. generates an error (which one?)

Show answer

Exercise - good manners

Write some code which given two lists la and lb MODIFY la adding all the elements of lb and then reversing the whole list.

  • you code must work with any la and lb

  • DO NOT modify lb

Example - given:

la = ['g','o','o','d']
lb = ['m','a','n','n','e','r','s']

After your code, it must print:

>>> print('la=',la)
la= ['s', 'r', 'e', 'n', 'n', 'a', 'm', 'd', 'o', 'o', 'g']
>>> print('lb=',lb)
lb= ['m', 'a', 'n', 'n', 'e', 'r', 's']
Show solution
[64]:

la = ['g','o','o','d'] lb = ['m','a','n','n','e','r','s'] # write here

Exercise - precious things

Given two lists la and lb write some code which PRINTS a list with the elements of la and lb in reverse order.

  • DO NOT modify la and DO NOT modify lb

  • your code must work with any list la and lb

Example - given:

la = ['p','r','e','c','i','o','u','s']
lb = ['t','h','i','n','g','s']

After your code, it must print:

['s', 'g', 'n', 'i', 'h', 't', 's', 'u', 'o', 'i', 'c', 'e', 'r', 'p']
Show solution
[65]:

la = ['p','r','e','c','i','o','u','s'] lb = ['t','h','i','n','g','s'] # write here

Exercise - powers

The following code uses some insert which as we already said it is not very efficient. Try to understand what it does, and rewrite it using only append and reverse

  • your code must work for any value of x

[66]:
x = 2
la = [x]
la.insert(0,la[0]*2)
la.insert(0,la[0]*2)
la.insert(0,la[0]*2)
la.insert(0,la[0]*2)
print(la)
[32, 16, 8, 4, 2]
Show solution
[67]:

x = 2 la = [x] # write here

sort method

If a list contains homogenous elements, it is possible to sort it rapidly with the sort method, which MODIFIES the list on which it is called (also called sorting in-place):

[68]:
la = [8,6,7,9]
[69]:
la.sort()  # NOTE: sort returns nothing !!!
[70]:
la
[70]:
[6, 7, 8, 9]

Strings are also sortable

[71]:
lb = ['Boccaccio', 'Alighieri', 'Manzoni', 'Leopardi']
[72]:
lb.sort()
[73]:
lb
[73]:
['Alighieri', 'Boccaccio', 'Leopardi', 'Manzoni']

A list with non-comparable elements it’s not sortable, and Python will complain:

[74]:
lc = [3,4,'cabbage',7,'potatoes']
>>> lc.sort()

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-288-0cabfae30939> in <module>
----> 1 lc.sort()

TypeError: '<' not supported between instances of 'str' and 'int'

Optionally, for reverse order you can pass the parameter reverse=True :

[75]:
la = [4,2,5,3]
la.sort(reverse=True)
[76]:
la
[76]:
[5, 4, 3, 2]

Custom sorting

If you have custom needs like for example a lists of strings in the format 'name surname' that you want to sort according to the surname, you should use optional parameter key with lambda functions, see Python docs

Exercise - numlist

Given the list la = [10, 60, 72, 118, 11, 71, 56, 89, 120, 175]

  1. finds the min, max and the median value (HINT: sort it and extract the right values)

  2. create a list only with elements at even indexes (i.e. [10, 72, 11, ..], note that “..” means the list is still not complete!) and ricalculates the values of min, max and median

  3. redo the same with the elements at odd indexes (i.e. [60, 118,..])

You should obtain:

original:    [10, 60, 72, 118, 11, 71, 56, 89, 120, 175]
even:        [10, 72, 11, 56, 120]
odd:         [60, 118, 71, 89, 175]

sorted:      [10, 11, 56, 60, 71, 72, 89, 118, 120, 175]
sorted even: [10, 11, 56, 72, 120]
sorted odd:  [60, 71, 89, 118, 175]

original:    Min: 10  Max. 175  Median:  72
even:        Min: 10  Max. 120  Median:  56
odd:         Min: 60  Max. 175  Median:  89
Show solution
[77]:


la = [10, 60, 72, 118, 11, 71, 56, 89, 120, 175] # write here

join - build strings from lists

Given a string to use as separator, and a sequence like for example a list la which only contains strings, it’s possible to concatenate them into a (new) string with join method:

[78]:
la = ["When", "the", "sun", "raises"]

'SEPARATOR'.join(la)
[78]:
'WhenSEPARATORtheSEPARATORsunSEPARATORraises'

As separator we can put any character, like a space:

[79]:
' '.join(la)
[79]:
'When the sun raises'

Note the original list is not modified:

[80]:
la
[80]:
['When', 'the', 'sun', 'raises']

QUESTION: What does this code produce?

''.join(['a','b','c']).upper()
  1. an error (which one?)

  2. a string (which one?)

  3. a list (which one?)

Show answer

QUESTION: What does this code produce?

'a'.join('KRT') + 'E'
  1. a string (which one?)

  2. an error (which one?)

  3. a list (which one?)

Show answer

QUESTION: What does this code produce?

'\''.join('mmmm')
  1. an error (which one?)

  2. a string (which one?)

Show answer

QUESTION: Given any string s and a list of strings la of at least two characters, the following code will always give us the same result - which one? (think about it, and if you don’t know how to answer try putting random values for s and la)

len(s) <= len(s.join(la))
  1. an errore (which one?)

  2. a stringa (which one?)

  3. something else (what?)

Show answer

Exercise - barzoletta

Given the string

sa = 'barzoletta'

write some code which creates a NEW string sb by changing the original string in such a way it results:

>>> print(sb)
'barzelletta'
  • USE the method insert and cell reassignment

  • NOTE: you cannot use them an a string, because it is IMMUTABLE - you will then first convert the string to a list

Show solution
[81]:


sa = 'barzoletta' # write here

Exercise - dub dab dib dob

Write some code which given a list of strings la, associates to variable s a string with the concatenated strings, separating them with a comma and a space.

Example - given:

la = ['dub', 'dab','dib', 'dob']

After your code, you should obtain this:

>>> print(s)
dub, dab, dib, dob
>>> len(s)
18
Show solution
[82]:

la = ['dub', 'dab','dib', 'dob'] # write here

Exercise - ghirigori

Given a list of strings la and a list with three separators seps, write some code which prints the elements of la separated by first separator, followed by the second separator, followed by the elements of la separated by the third separator.

  • your code must work with any list la and seps

Example - given:

la = ['ghi','ri','go','ri']
seps = [',','_','+']

After your code, it must print:

ghi,ri,go,ri_ghi+ri+go+ri
Show solution
[83]:


la = ['ghi','ri','go','ri'] seps = [',','_','+'] # write here

Exercise - welldone

Given the list:

la = ["walnut", "eggplant", "lemon", "lime", "date", "onion", "nectarine", "endive" ]:
  1. Create another list (call it new) containing the first character of every element of la

  2. Add a space to new at position 4 and attach an exclamation mark ('!') at the end

  3. Print the list

  4. Print the list content by joining all elements with an empty space

You should get:

['w', 'e', 'l', 'l', ' ', 'd', 'o', 'n', 'e', '!']

 well done!
Show solution
[84]:

la = ["walnut", "eggplant", "lemon", "lime", "date", "onion", "nectarine", "endive" ] # write here

copy method

If we want to copy a mutable data structure, we can use the .copy() method, which performs a so-called shallow copy. Let’s see what it means.

Let’s start with a simple case, for example a list of immutable objects like strings we can visualize in Python Tutor:

[85]:
satellites = ["Hubble", "Sputnik 1"]

copia = satellites.copy()

jupman.pytut()
[85]:
Python Tutor visualization

We clearly see how a completely new memory region was created. If we later try to modify the copy, we will see the original is not changed:

[86]:
satellites = ["Sputnik 1", "Hubble"]

my_copy = satellites.copy()

my_copy.append("James Webb")

jupman.pytut()
[86]:
Python Tutor visualization

copy is shallow

So far, we didn’t notice any particular problem. But what happens if we try copy() on a list which contains other lists, in other words, other mutable elements, and then try mutating one of the two?

[87]:

biglistA = [ ['Pay', 'attention'], ['to', 'where'], ['the', 'arrows', 'point to'] ] biglistB = biglistA.copy() biglistA[2][0] = 'CAREFUL!' # we write into the original... print(biglistA) print(biglistB) jupman.pytut()
[['Pay', 'attention'], ['to', 'where'], ['CAREFUL!', 'arrows', 'point to']]
[['Pay', 'attention'], ['to', 'where'], ['CAREFUL!', 'arrows', 'point to']]
[87]:
Python Tutor visualization

Note we have two big lists containing cells that point to shared sublists: as a matter of fact, by writing into a subcell of biglistA we also write into biglistB!

In other words, .copy() performs only a shallow copy, for a proper deep copy we will need to find some other way!

deepcopy function

To avoid sharing problems we can use the so-called deep copy, available in the function deepcopy from module copy

WARNING: deepcopy IS NOT a list method!

Let’s try again the example with copy.deepcopy: we will now get completely distinct data structures:

[88]:
# first we import `copy`, which is a PYTHON MODULE
import copy

biglistA = [ ['Pay', 'attention'],
             ['to', 'where'],
             ['the', 'arrows', 'point to']
]

# then we call its function deepcopy, passing the parameter biglistA:

biglistB = copy.deepcopy(biglistA)
biglistA[2][0]  = 'CAREFUL!'  # we write into the original...

print(biglistA)
print(biglistB)

jupman.pytut()
[['Pay', 'attention'], ['to', 'where'], ['CAREFUL!', 'arrows', 'point to']]
[['Pay', 'attention'], ['to', 'where'], ['the', 'arrows', 'point to']]
[88]:
Python Tutor visualization

Continue

You can find more exercises in the worksheet Lists 4 - Search methods