Pythonic constructions
Accessing last elements
In Python, we can access the last elements of a list with index len(L) - 1
, len(L) - 2
, etc. This is not Pythonic.
L = [1, 2, 1, 3, 4, 5, 8, 42]
L[len(L)-1]
This is the Pythonic option:
L = [1, 2, 1, 3, 4, 5, 8, 42]
L[-1]
Of course, the same trick works for tuples:
t = (1, 2, 1, 3, 4)
t[-1]
Slices
We can obtain slices of a list like this:
L = [1, 2, 1, 3, 4, 5, 8, 42]
L[2:5]
[1, 4]
Quiz
- What are the outputs of the following programs?
L = [1, 2, 1, 3, 4]
L[2] = 500
L
[1, 2, 500, 3, 4]
L = [1, 2, 1, 3, 4]
M = L[2:4]
M[0] = 500
M
[500, 3]
L = [1, 2, 1, 3, 4]
M = L[2:4]
M[0] = 500
L
[1, 2, 1, 3, 4]
We can obtain a slice of a tuple like this:
T = (1, 2, 8, 45, 2)
T[2:5]
(8, 45, 2)
T[:2]
(1, 2)
T[2:]
(8, 45, 2)
More generally, the syntax is L[start:stop:step]
, where the element at index stop
is excluded.
L = list(range(0, 21))
L[1:8:2]
L = list(range(0, 21))
L[-3::-3]
L = list(range(0, 21))
L[-3:0:-3]
Sum of elements
Python provides sum
to sum elements of a list, a tuple:
sum([1, 2, 5])
8
sum((1, 2, 5))
8
sum({1, 1, 2, 5})
List/set comprehensions
This code is super ugly:
squares = []
for i in range(10):
squares.append(i**2)
squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Instead, we can use list comprehension. See https://peps.python.org/pep-0202/
[i*2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
List comprehension comes from the language SETL (SET Language) in 1969, where we can write:
{x: x in {2..n} | forall y in {2..x-1} | x mod y /= 0}
It is also present in Haskell:
s = [x | x <- [0..], x^2 > 3].
A = [[0 for i in range(10)] for j in range(5)]
A
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
A = [[0 for i in range(10)] for j in range(5)]
A[0].append(1)
A
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
[i for i in range(20) if i%2 == 0]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Be careful with *
!
[[0]*10]*5
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
A = [[0]*10]*5
A[0][0] = 1
A
[[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
Here is an example of set comprehension.
{c for c in "Hello world!"}
{' ', '!', 'H', 'd', 'e', 'l', 'o', 'r', 'w'}
Here is an example of dictionary comprehension.
s = "hello world!"
{c: s.count(c) for c in s}
{'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1, '!': 1}
Generators by comprehension
We can also write a sort of list by comprehension but the list itself is never created.
(i*2 for i in range(100))
<generator object <genexpr> at 0x7fd100179eb0>
They can even contain an infinite number of objects:
import itertools
(i*2 for i in itertools.count())
<generator object <genexpr> at 0x7fd100127120>
Unpacking tuples
point = (42, 2)
x, y = point
print(x)
42
x, y = [10, 2]
x
10
x, y = [1, 2, 3]
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[28], line 1
----> 1 x, y = [1, 2, 3]
ValueError: too many values to unpack (expected 2)
x, _, y = [1, 2, 3]
y
3
Pattern matching
Here is an example of real pattern matching.
i=0
match i:
case 0: print("zero")
case _: print("non zero")
Functional programming
Python has filter, map, etc. even if they are not very useful because of list/set comprehension.
filter(lambda x: x % 2 == 0, [1, 2, 4, 6])
<filter at 0x7fd1002eafa0>
for x in filter(lambda x: x % 2 == 0, [1, 2, 4, 6]):
print(x)
2
4
6
map(lambda x: 2*x, [1, 2, 3])
<map at 0x7fd0e37be6d0>
list(map(lambda x: x**2, [1, 2, 3]))
[1, 4, 9]