Python Language List: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
 
(90 intermediate revisions by the same user not shown)
Line 2: Line 2:
* [[Python_Language#List|Python Language]]
* [[Python_Language#List|Python Language]]
* [[Python_Language_Dictionary#Overview|Dictionary]]
* [[Python_Language_Dictionary#Overview|Dictionary]]
=Overview=
=Overview=
A list is a mutable [[Python_Language#Sequence_Types|sequence type]] that contains zero or more elements and whose elements can be of the same type or different types. The elements of a list are ordered. As mentioned, the list is mutable, in that a list can be changed in-place, new elements can be added to it, and existing elements can be overwritten. Unlike a [[Python Language Set|set]], a list can contain the same element multiple times, a list element does not need to be unique in the list.
A list is a mutable [[Python_Language#Sequence_Types|sequence type]] that contains zero or more elements and whose elements can be of the same type or different types. The elements of a list are ordered. A list can be changed in-place, new elements can be added to it, and existing elements can be overwritten. Unlike a [[Python Language Set|set]], a list can contain the same element multiple times, a list element does not need to be unique in the list.


=List <tt>type()</tt>=
=List <tt>type()</tt>=
The function <code>type()</code> applied to a list returns:
The function <code>type()</code> applied to a list returns:
<font size=-1>
<font size=-2>
<class 'list'>
<class 'list'>
</font>
</font>


Line 24: Line 23:
   ...
   ...
</syntaxhighlight >
</syntaxhighlight >
=List Comparison=
Two different list instances that contain the same values in the same order are considered equal:
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c']
l2 = ['a', 'b', 'c']
assert l == l2 # passes
</syntaxhighlight>


=Create a List=
=Create a List=
Line 40: Line 47:
empty_list = list()
empty_list = list()
</syntaxhighlight>
</syntaxhighlight>
The <code>list()</code> function converts the data types to lists. The data types that can be converted are:
The <code>list()</code> function converts the data types to lists. <code>list()</code> applied to a list creates a copy of that list. The data types that can be converted are:
===String to List===
===String to List===
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
s = 'abc'
s = 'abc'
l = list(s) # l is ['a', 'b', 'c']
l = list(s)
assert l == ['a', 'b', 'c']
</syntaxhighlight>
</syntaxhighlight>
===Tuple to List===
===Tuple to List===
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
t = ('a', 'b', 'c')
t = ('a', 'b', 'c')
l = list(t) # l is ['a' ,'b', 'c']
l = list(t)
assert l == ['a' ,'b', 'c']
</syntaxhighlight>
===Pass a Generator Expression===
<syntaxhighlight lang='py'>
gen = range(10)
l = list(gen) # creates a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] list
</syntaxhighlight>
Also see: {{Internal|Python_Generators#Overview|Generators}}
 
==Create a List of Specific Size==
To create a list of specific size, so arbitrary elements can be set in place at a specific index with <code>list[offset] = ...</code>, use this syntax:
<syntaxhighlight lang='py'>
l = [None] * 5
l[2] = 'A' # [None, None, 2, None, None]
</syntaxhighlight>
 
==Create a Copy of a List==
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c']
l2 = l.copy()
 
l[0] = 'x'
assert 'x' == l[0]
assert 'a' == l2[0]
</syntaxhighlight>
 
==Create a List and Initialize it with a Function Return Values==
<syntaxhighlight lang='py'>
import random
data = [random.randint(0, 10) for i in range(10)]
</syntaxhighlight>
</syntaxhighlight>


=Access a List=
=Access a List=
==Test for Empty List==
==Test for Empty List==
==Test for Existence of an Element in List==
==<span id='Test_for_Existence_of_an_Element_in_List'></span>Test for Existence of an Element in List with the <tt>in</tt> Keyword==
A Python idiomatic way to test whether a value is in the list is using <code>in</code>:
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c', 'b', 'd']
if 'a' in l:
  print("'a' found")
else:
  print("'a' NOT found")
if 'x' in l:
  print("'x' found")
else:
  print("'x' NOT found")
</syntaxhighlight>
<code>not in</code> can be used to assess non-existence.
 
The offset of an element with a certain value can be returned by calling <code>index()</code>.
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c', 'b', 'd']
assert 1 == l.index('b')
</syntaxhighlight>
If the element exists in list, the <code>index()</code> returns the offset of the first value in the list, in case the value exists more than once. If the value does not exist, the method will throw <code>ValueError: '...' is not in list</code>.
 
==Access an Element in List==
==Access an Element in List==
The element of a list can be accessed using the <code>[<I><offset></I>]</code> syntax. The offset is zero-based, and it can be positive or negative.  
The element of a list can be accessed using the <code>[<I><offset></I>]</code> syntax. The offset is zero-based, and it can be positive or negative.  
Line 64: Line 123:
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c']
l = ['a', 'b', 'c']
print(l[-1]) # displays "c"
assert 'c' == l[-1]
print(l[-2]) # displays "b"
assert 'b' == l[-2]
</syntaxhighlight>
</syntaxhighlight>
⚠️ In case of both positive and negative indices, the offset should be valid. If the indices fall outside of the list's bounds, <code>IndexError: list index out of range</code> exception is thrown.
⚠️ In case of both positive and negative indices, the offset should be valid. If the indices fall outside of the list's bounds, <code>IndexError: list index out of range</code> exception is thrown.
Line 72: Line 131:
The number of elements is given by the <code>len()</code> function:
The number of elements is given by the <code>len()</code> function:
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
l = [...]
l = ['a', 'b', 'c']
print(len(l))
assert 3 == len(l)
</syntaxhighlight>
</syntaxhighlight>


==Iterate over a List==
==Count Occurrences of a Value with <tt>count()</tt>==
<syntaxhighlight lang='py'>
l = ['A', 'B', 'C']
for i, e in enumerate(l):
    print(f'index: {i}, element: {e}')
</syntaxhighlight>
==Slices==
A sub-sequence of a list can be extracted with a slice. The slice <code>[<start-index>:<end-index>:<step>]</code> specified the index of the last element, and the index of the first element '''not included''' in slice, and the step. The step is optional, the default value is 1.
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c', 'd', 'e', 'f']
print(l[:]) # starts from the beginning and ends after the end of the list, prints ['a', 'b', 'c', 'd', 'e', 'f']
print(l[2:4]) # prints ['c', 'd']
print(l[2:4:2]) # prints ['c']
</syntaxhighlight>
The step can be negative, which means the slice starts at the end and goes from right to left.
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c', 'd', 'e', 'f']
l = ['a', 'b', 'c', 'a']
print(l[::-1]) # prints ['f', 'e', 'd', 'c', 'b', 'a']
assert 2 == l.count('a')
</syntaxhighlight>
</syntaxhighlight>


<font color=darkkhaki>
==Iterate over a List==
{{Internal|Python_Language#Loops_and_Iterations|Python Language &#124; Loops and Iterations}}


Assign the sublist to <code>l</code>:
==<span id='Extract_Elements_from_the_Tail_of_the_List_Starting_with_a_Certain_Index'></span><span id='Extract_Elements_from_the_Head_of_the_List_Counting_from_the_Tail'></span>Slices==
<syntaxhighlight lang='py'>
{{Internal|Slicing Lists and Tuples in Python#Overview|Slicing Lists and Tupes in Python}}
l = l[:-1]
</syntaxhighlight>
</font>


=Modify a List=
=Modify a List=
Line 115: Line 158:


===<span id='append'></span>Append an Element===
===<span id='append'></span>Append an Element===
The traditional way of adding items to a list is to <code>append()</code> them one by one to the end of the list. The invocation increases the length of the list.
The traditional way of adding items to a list is to <code>append()</code> them one by one to the end of the list. The invocation modifies the list in-place and increases the length of the list.
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
l = [1, 2, 3]
l = [1, 2, 3]
Line 122: Line 165:
</syntaxhighlight>
</syntaxhighlight>
<code>append()</code> adds the argument to the end of the list, as one element, even if it's another list. To extend the list by adding the elements individually, use <code>[[#extend|extend()]]</code> or <code>[[#extend|+=]]</code>.
<code>append()</code> adds the argument to the end of the list, as one element, even if it's another list. To extend the list by adding the elements individually, use <code>[[#extend|extend()]]</code> or <code>[[#extend|+=]]</code>.
⚠️ Do not use <code>append()</code> to append the content of another list.  <code>append()</code> works only for individual elements, if used with a list, it appends the list itself, not its elements. Use <code>[[#Append_a_List|extent()]]</code> instead.


===<span id='extend'></span>Append a List===
===<span id='extend'></span>Append a List===
Line 130: Line 175:
l1.extend(l2)
l1.extend(l2)
print(l1) # will display [1, 2, 3, 10, 20]
print(l1) # will display [1, 2, 3, 10, 20]
</syntaxhighlight>
Note that the argument of the <code>extend()</code> function may not be <code>None</code>. If that happens, we get:
<syntaxhighlight lang='text'>
TypeError: 'NoneType' object is not iterable
</syntaxhighlight>
</syntaxhighlight>
The <code>extend()</code> function is equivalent with the <code>+=</code> operator:
The <code>extend()</code> function is equivalent with the <code>+=</code> operator:
Line 138: Line 187:
print(l1) # will display [1, 2, 3, 10, 20]
print(l1) # will display [1, 2, 3, 10, 20]
</syntaxhighlight>
</syntaxhighlight>
===<span id='insert'></span>Insert an Element in the Middle of a List===
===<span id='insert'></span>Insert an Element in the Middle of a List===
<code>insert(offset, element)</code> inserts an element in the middle of the list. For a 0 offset, the function will insert the element at the beginning of the list. If the offset falls outside the list boundaries, it will add at the end of the list without throwing an exception. When an item is deleted from a list, the items that follow it shift left to take its position and the length of the list decreases by one.
<code>insert(offset, element)</code> inserts an element in the middle of the list. ⚠️ <code>insert()</code> will increase the list length. For a 0 offset, the function will insert the element at the beginning of the list. If the offset falls outside the list boundaries, it will add at the end of the list without throwing an exception. When an item is deleted from a list, the items that follow it shift left to take its position and the length of the list decreases by one.
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
l1 = [1, 2, 3]
l1 = [1, 2, 3]
Line 149: Line 199:
print(l1) # will display [40, 1, 10, 2, 3, 20]
print(l1) # will display [40, 1, 10, 2, 3, 20]
</syntaxhighlight>
</syntaxhighlight>
<tt>insert()</tt> is computationally expensive compared with <code>append()</code> because reference to subsequent elements have to be shifted internally to make room for the new element. If you need to insert elements at both the beginning and end of a sequence, you may wish to explore <code>collections.deque()</code>, a double-ended queue, which is optimized for this purpose, available in Python Standard library.


===Delete an Element by Offset===
===Delete an Element by Offset===
Line 158: Line 209:
del l[-1] # the list is now [2]
del l[-1] # the list is now [2]
</syntaxhighlight>
</syntaxhighlight>
===Delete an Element by its Value===
===Remove (Delete) an Element by its Value===
<code>remove()</code> deletes an element from a list based on its value. If more than one elements have the same value, only the first one is removed.
<code>remove()</code> deletes an element from a list based on its value and compacts the list.
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c']
l.remove('b')
assert l == ['a', 'c']
</syntaxhighlight>
If more than one elements have the same value, only the first one is removed:
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c', 'b', 'd']
l.remove('b')
assert l == ['a', 'c', 'b', 'd']
</syntaxhighlight>
If the element is not present, the method raises <code>ValueError</code>:
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c']
try:
  l.remove('d')
except ValueError:
  pass
assert l == ['a', 'b', 'c']
</syntaxhighlight>
 
===Return and Remove an Element with <tt>pop()</tt>===
===Return and Remove an Element with <tt>pop()</tt>===
An element identified by offset can be returned and deleted from the list. Positives and negative offsets work.
An element identified by offset can be returned and deleted from the list with <code>pop()</code>. The operation is inverse to <code>[[#Insert_an_Element_in_the_Middle_of_a_List|insert()]]</code>. Positives and negative offsets work.
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
l = [1, 2, 3]
l = [1, 2, 3]
print(l.pop(1)) # displays 2
print(l.pop(1)) # displays 2
print(l) # displays [1, 3]
print(l) # displays [1, 3]
</syntaxhighlight>
<code>pop()</code> without argument implies -1: the last element of the list will be returned and deleted.
===Reverse a List In-place===
A list can be reversed '''in-place''' with <code>reverse()</code>.
<syntaxhighlight lang='py'>
l = [1, 2, 3]
l.reverse()
print(l) # displays [3, 2, 1]
</syntaxhighlight>
⚠️ <code>reverse()</code> returns <code>None</code>, not a list! The reversal is done in place. The fact that the method does not return anything is counterintuitive, it cannot use as part of a flow syntax.
Note that the list can be iterated in reverse order with the built-in <code>[[#Iterate_over_a_List_in_Reversed_Order|reversed()]]</code>.
===Remove an Element while Iterating===
Evaluate the list by index, going backwards. Note that if we're storing the processed and deleted elements into secondary storage, at the end it must be revered to preserve the original order.
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c', 'a', 'd']
for i in range(len(l)-1, -1, -1):
    if l[i] == 'a':
        del l[i]
assert l == ['b', 'c', 'd']
</syntaxhighlight>
</syntaxhighlight>


==Delete All Elements==
==Delete All Elements==


=Copy a List=
<syntaxhighlight lang='py'>
lst = [2, 3, 5]
lst_copy = lst.copy()
</syntaxhighlight>
=Printing Lists=
<font color=darkkhaki>If <code>print()</code> is called on list that contain custom class instances, <code>__str()__</code> does not seem to be called on instances.</font>
=Multi-Dimensional Lists=
<syntaxhighlight lang='py'>
m = [[1, 2, 3],[4, 5, 6],[7, 8, 9]]
print(m[2][1]) # prints 8
</syntaxhighlight>
=List Processing=
=List Processing=
==<tt>split()</tt>, <tt>join()</tt>==
==<tt>split()</tt>, <tt>join()</tt>==
Line 182: Line 293:
l = s.split(',') # l is ['a', '', 'b', 'c']
l = s.split(',') # l is ['a', '', 'b', 'c']
</syntaxhighlight>
</syntaxhighlight>
The string can then be put back together with <code>join()</code>. Note that <code>join()</code> is a string method, not a list method, so it should be applied to the separator string. The elements of the list must be strings, otherwise an exception is thrown: <code>TypeError: sequence item 0: expected str instance, int found</code>.
<syntaxhighlight lang='py'>
l = ['a', 'b', 'c', 'd']
s = ', '.join(l)
print(s) # will display a, b, c, d
</syntaxhighlight>
<code>join()</code> being a string method, can be used with other [[Python_Language#Iterable_Types|iterable types]] like [[Python Language Tuple#Overview|tuple]] or [[Python Language Set#Overview|set]].


==Sorting==
==<span id='Sorting'></span>Sort==
==TO DEPLETE==
There are two methods that can be used to sort lists: <code>list.sort()</code> and <code>sorted()</code>. The <code>sort()</code> sorts the list in-place, while <code>[[Python_Built-In_Function_sorted()#Overview|sorted()]]</code> creates a copy of the list and leaves the argument unmodified:
<syntaxhighlight lang='py'>
l = ['c', 'b', 'a']
l.sort()
assert ['a', 'b', 'c'] == l
</syntaxhighlight>
The default sort order is ascending, but if the <code>sort(reverse=True)</code> is invoked with <code>reverse=True</code>, the order will be switched to descending.
<syntaxhighlight lang='py'>
l = ['c', 'b', 'a']
l2 = sorted(l)
assert ['c', 'b', 'a'] == l
assert ['a', 'b', 'c'] == l2
</syntaxhighlight>
For a discussion on how elements are compared, see: {{Internal|Python_Built-In_Function_sorted()#Comparing_Elements|<tt>sorted()</tt> &#124; Comparing Elements}}
 
==Iterate over a List in Reversed Order==
<font color=darkkhaki>TO PROCESS [[PyOOP]] "Reversed"</font>


===Join the List Elements in a String===
<code>[[Python_Language_Functions#reversed|reversed()]]</code> built-in can be used to iterate over a list in reversed order:
Join the elements of the given list in a string, using '-' as separator:
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
li = ['a', 'b']
l = ['a', 'b', 'c']
s = '-'.join(li)
for i in reversed(l):
  ...
</syntaxhighlight>
</syntaxhighlight>
Only works if the list elements are strings.


===Extract Elements from the Tail of the List Starting with a Certain Index===
The list is left unchanged. Note that a list can be revered in-place with <code>[[#Reverse_a_List_In-place|reverse()]]</code>
 
==Access the Index and the Element at the Same Time with enumerate()==
<font color=darkkhaki>TO PROCESS [[PyOOP]] "Enumerate"</font>
 
The <code>[[Python_Language_Functions#enumerate|enumerate()]]</code> built-in function gives access to the elements of the list and their index at the same time.
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
l = [1, 2, 3]
l = ['a', 'b', 'c']
print(l[0:]) # prints [1, 2, 3]
for i, e in enumerate(l):
print(l[1:]) # prints [2, 3]
    print(f'index: {i}, element: {e}')
print(l[2:]) # prints [3]
</syntaxhighlight>
print(l[3:]) # prints [] (empty list)
 
print(l[4:]) # prints [] (empty list)
==List Concatenation with <tt>+</tt>==
Two lists can be concatenated with the <code>+</code> operator:
<syntaxhighlight lang='py'>
['a', 'b', 'c'] + ['x', 'y']
</syntaxhighlight>
</syntaxhighlight>
Not that list concatenation by addition is expensive since a new list must be created and the objects copied over. Using <code>[[#Append_a_List|extend()]]</code> to append elements to an existing list is usually preferable.


===Extract Elements from the Head of the List Counting from the Tail===
=Subclass a List=
TODO
=Copy a List=
=Multi-Dimensional Lists=
<syntaxhighlight lang='py'>
<syntaxhighlight lang='py'>
m = [[1, 2, 3],[4, 5, 6],[7, 8, 9]]
class MockList(list):
print(m[2][1]) # prints 8
    # noinspection PyUnusedLocal
    def __init__(self, *args, **kwargs):
        super().__init__()
        milestone = kwargs.get('milestone')
        if milestone is None:
            self._storage = test_issues.copy()
        elif milestone == '*':
            self._storage = [get_mock_issue(1, 'issue 1')]
        elif milestone == 'none':
            self._storage = [get_mock_issue(2, 'issue 2')]
        elif isinstance(milestone, Mock):
            self._storage = [get_mock_issue(3, 'issue 3')]
        else:
            raise ValueError(f'unexpected milestone: {milestone}')
 
    def __str__(self):
        return str(self._storage)
 
    def __len__(self, *args, **kwargs):
        return len(self._storage)
 
    def __getitem__(self, y):
        return self._storage.__getitem__(y)
 
    def __iter__(self, *args, **kwargs):
        return self._storage.__iter__()
</syntaxhighlight>
</syntaxhighlight>

Latest revision as of 17:25, 17 May 2024

Internal

Overview

A list is a mutable sequence type that contains zero or more elements and whose elements can be of the same type or different types. The elements of a list are ordered. A list can be changed in-place, new elements can be added to it, and existing elements can be overwritten. Unlike a set, a list can contain the same element multiple times, a list element does not need to be unique in the list.

List type()

The function type() applied to a list returns:

<class 'list'>

To check whether an instance is a list:

i = ...
if type(i) is list:
  ...

For list subclasses:

i = ...
if isinstance(i, list):
  ...

List Comparison

Two different list instances that contain the same values in the same order are considered equal:

l = ['a', 'b', 'c']
l2 = ['a', 'b', 'c']
assert l == l2 # passes

Create a List

A list can be created with the [] syntax, with the list() functions and with list comprehensions.

Create a List with []

A list can be created specifying the list elements, separate them by comma and enclose them in square brackets.

empty_list = []
some_list = ['A', 'B', 'C']
some_other_list = ['A', 2, 3.0, ['B', 4]]

Create a List or Convert other Data Type to a List with list()

An empty list can be created with the list() function:

empty_list = list()

The list() function converts the data types to lists. list() applied to a list creates a copy of that list. The data types that can be converted are:

String to List

s = 'abc'
l = list(s)
assert l == ['a', 'b', 'c']

Tuple to List

t = ('a', 'b', 'c')
l = list(t)
assert l == ['a' ,'b', 'c']

Pass a Generator Expression

gen = range(10)
l = list(gen) # creates a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] list

Also see:

Generators

Create a List of Specific Size

To create a list of specific size, so arbitrary elements can be set in place at a specific index with list[offset] = ..., use this syntax:

l = [None] * 5
l[2] = 'A' # [None, None, 2, None, None]

Create a Copy of a List

l = ['a', 'b', 'c']
l2 = l.copy()

l[0] = 'x'
assert 'x' == l[0]
assert 'a' == l2[0]

Create a List and Initialize it with a Function Return Values

import random
data = [random.randint(0, 10) for i in range(10)]

Access a List

Test for Empty List

Test for Existence of an Element in List with the in Keyword

A Python idiomatic way to test whether a value is in the list is using in:

l = ['a', 'b', 'c', 'b', 'd']
if 'a' in l:
  print("'a' found")
else:
  print("'a' NOT found")
if 'x' in l:
  print("'x' found")
else:
  print("'x' NOT found")

not in can be used to assess non-existence.

The offset of an element with a certain value can be returned by calling index().

l = ['a', 'b', 'c', 'b', 'd']
assert 1 == l.index('b')

If the element exists in list, the index() returns the offset of the first value in the list, in case the value exists more than once. If the value does not exist, the method will throw ValueError: '...' is not in list.

Access an Element in List

The element of a list can be accessed using the [<offset>] syntax. The offset is zero-based, and it can be positive or negative.

l = ['a', 'b', 'c']
print(l[0])

Negative indices count backward from the end, the last element is identified with a -1 index. Think about it as index = len(list) - negative-index.

l = ['a', 'b', 'c']
assert 'c' == l[-1]
assert 'b' == l[-2]

⚠️ In case of both positive and negative indices, the offset should be valid. If the indices fall outside of the list's bounds, IndexError: list index out of range exception is thrown.

Length of a List

The number of elements is given by the len() function:

l = ['a', 'b', 'c']
assert 3 == len(l)

Count Occurrences of a Value with count()

l = ['a', 'b', 'c', 'a']
assert 2 == l.count('a')

Iterate over a List

Python Language | Loops and Iterations

Slices

Slicing Lists and Tupes in Python

Modify a List

Modify Individual Elements

Modify an Element Identified by [offset]

An element of a list can be modified using the [<offset>] syntax. The offset is zero-based, and it can be positive or negative, as described in Access an Element in List.

l = ['a', 'b', 'c']
l[1] = 'd'
print(l[1])

Append an Element

The traditional way of adding items to a list is to append() them one by one to the end of the list. The invocation modifies the list in-place and increases the length of the list.

l = [1, 2, 3]
l.append(10)
print(l) # will display [1, 2, 3, 10]

append() adds the argument to the end of the list, as one element, even if it's another list. To extend the list by adding the elements individually, use extend() or +=.

⚠️ Do not use append() to append the content of another list. append() works only for individual elements, if used with a list, it appends the list itself, not its elements. Use extent() instead.

Append a List

A list can be extended with another list with the extend() function:

l1 = [1, 2, 3]
l2 = [10, 20]
l1.extend(l2)
print(l1) # will display [1, 2, 3, 10, 20]

Note that the argument of the extend() function may not be None. If that happens, we get:

TypeError: 'NoneType' object is not iterable

The extend() function is equivalent with the += operator:

l1 = [1, 2, 3]
l2 = [10, 20]
l1 += l2
print(l1) # will display [1, 2, 3, 10, 20]

Insert an Element in the Middle of a List

insert(offset, element) inserts an element in the middle of the list. ⚠️ insert() will increase the list length. For a 0 offset, the function will insert the element at the beginning of the list. If the offset falls outside the list boundaries, it will add at the end of the list without throwing an exception. When an item is deleted from a list, the items that follow it shift left to take its position and the length of the list decreases by one.

l1 = [1, 2, 3]
l1.insert(1, 10)
print(l1) # will display [1, 10, 2, 3]
l1.insert(1000, 20)
print(l1) # will display [1, 10, 2, 3, 20]
l1.insert(-1000, 40)
print(l1) # will display [40, 1, 10, 2, 3, 20]

insert() is computationally expensive compared with append() because reference to subsequent elements have to be shifted internally to make room for the new element. If you need to insert elements at both the beginning and end of a sequence, you may wish to explore collections.deque(), a double-ended queue, which is optimized for this purpose, available in Python Standard library.

Delete an Element by Offset

To delete an element by offset use del list_name[<offset>]. The offset can be positive or negative. Using -1 deletes the last element from the list.

l = [1, 2, 3]
del l[0] # the list is now [2, 3]
del l[-1] # the list is now [2]

Remove (Delete) an Element by its Value

remove() deletes an element from a list based on its value and compacts the list.

l = ['a', 'b', 'c']
l.remove('b')
assert l == ['a', 'c']

If more than one elements have the same value, only the first one is removed:

l = ['a', 'b', 'c', 'b', 'd']
l.remove('b')
assert l == ['a', 'c', 'b', 'd']

If the element is not present, the method raises ValueError:

l = ['a', 'b', 'c']
try:
  l.remove('d')
except ValueError:
  pass
assert l == ['a', 'b', 'c']

Return and Remove an Element with pop()

An element identified by offset can be returned and deleted from the list with pop(). The operation is inverse to insert(). Positives and negative offsets work.

l = [1, 2, 3]
print(l.pop(1)) # displays 2
print(l) # displays [1, 3]

pop() without argument implies -1: the last element of the list will be returned and deleted.

Reverse a List In-place

A list can be reversed in-place with reverse().

l = [1, 2, 3]
l.reverse()
print(l) # displays [3, 2, 1]

⚠️ reverse() returns None, not a list! The reversal is done in place. The fact that the method does not return anything is counterintuitive, it cannot use as part of a flow syntax.

Note that the list can be iterated in reverse order with the built-in reversed().

Remove an Element while Iterating

Evaluate the list by index, going backwards. Note that if we're storing the processed and deleted elements into secondary storage, at the end it must be revered to preserve the original order.

l = ['a', 'b', 'c', 'a', 'd']

for i in range(len(l)-1, -1, -1):
    if l[i] == 'a':
        del l[i]

assert l == ['b', 'c', 'd']

Delete All Elements

Copy a List

lst = [2, 3, 5]
lst_copy = lst.copy()

Printing Lists

If print() is called on list that contain custom class instances, __str()__ does not seem to be called on instances.

Multi-Dimensional Lists

m = [[1, 2, 3],[4, 5, 6],[7, 8, 9]]
print(m[2][1]) # prints 8

List Processing

split(), join()

A string can be converted into a list containing tokens delimited by separators in the string using the split() function. split() is a string function. The elements of the newly created list are strings.

s='a b c'
l = s.split(' ') # l is ['a', 'b', 'c']

If two separators occur in succession in the string, the list contains an empty string:

s='a,,b,c'
l = s.split(',') # l is ['a', '', 'b', 'c']

The string can then be put back together with join(). Note that join() is a string method, not a list method, so it should be applied to the separator string. The elements of the list must be strings, otherwise an exception is thrown: TypeError: sequence item 0: expected str instance, int found.

l = ['a', 'b', 'c', 'd']
s = ', '.join(l)
print(s) # will display a, b, c, d

join() being a string method, can be used with other iterable types like tuple or set.

Sort

There are two methods that can be used to sort lists: list.sort() and sorted(). The sort() sorts the list in-place, while sorted() creates a copy of the list and leaves the argument unmodified:

l = ['c', 'b', 'a']
l.sort()
assert ['a', 'b', 'c'] == l

The default sort order is ascending, but if the sort(reverse=True) is invoked with reverse=True, the order will be switched to descending.

l = ['c', 'b', 'a']
l2 = sorted(l)
assert ['c', 'b', 'a'] == l
assert ['a', 'b', 'c'] == l2

For a discussion on how elements are compared, see:

sorted() | Comparing Elements

Iterate over a List in Reversed Order

TO PROCESS PyOOP "Reversed"

reversed() built-in can be used to iterate over a list in reversed order:

l = ['a', 'b', 'c']
for i in reversed(l):
  ...

The list is left unchanged. Note that a list can be revered in-place with reverse()

Access the Index and the Element at the Same Time with enumerate()

TO PROCESS PyOOP "Enumerate"

The enumerate() built-in function gives access to the elements of the list and their index at the same time.

l = ['a', 'b', 'c']
for i, e in enumerate(l):
    print(f'index: {i}, element: {e}')

List Concatenation with +

Two lists can be concatenated with the + operator:

['a', 'b', 'c'] + ['x', 'y']

Not that list concatenation by addition is expensive since a new list must be created and the objects copied over. Using extend() to append elements to an existing list is usually preferable.

Subclass a List

class MockList(list):
    # noinspection PyUnusedLocal
    def __init__(self, *args, **kwargs):
        super().__init__()
        milestone = kwargs.get('milestone')
        if milestone is None:
            self._storage = test_issues.copy()
        elif milestone == '*':
            self._storage = [get_mock_issue(1, 'issue 1')]
        elif milestone == 'none':
            self._storage = [get_mock_issue(2, 'issue 2')]
        elif isinstance(milestone, Mock):
            self._storage = [get_mock_issue(3, 'issue 3')]
        else:
            raise ValueError(f'unexpected milestone: {milestone}')

    def __str__(self):
        return str(self._storage)

    def __len__(self, *args, **kwargs):
        return len(self._storage)

    def __getitem__(self, y):
        return self._storage.__getitem__(y)

    def __iter__(self, *args, **kwargs):
        return self._storage.__iter__()