A dict
is a mapping of keyvalue pairs
states = {
"CA": "California",
"DE": "Delaware",
"NY": "New York",
"TX": "Texas",
"WY": "Wyoming"
}
Dictionaries support similar operations as lists/strings:
>>> len(states)
5
>>> "CA" in states
True
>>> "ZZ" in states
False
words = {
"más": "more",
"otro": "other",
"agua": "water"
}
Ways to access a value by key:
>>> words["otro"]
'other'
>>> first_word = "agua"
>>> words[first_word]
'water'
>>> words["pavo"]
KeyError: pavo
>>> words.get("pavo", "🤔")
'🤔'
spiders = {
"smeringopus": {
"name": "Pale Daddy Longleg",
"length": 7
},
"holocnemus pluchei": {
"name": "Marbled cellar spider",
"length": (5, 7)
}
}
insects = {"spiders": 8, "centipedes": 100, "bees": 6}
for name in insects:
print(insects[name])
What will be the order of items?
8 100 6
Keys are iterated over in the order they are first added.
General syntax:
{key: value for <name> in <iter exp>}
Example:
{x: x*x for x in range(3,6)}
def prune(d, keys):
"""Return a copy of D which only contains key/value pairs
whose keys are also in KEYS.
>>> prune({"a": 1, "b": 2, "c": 3, "d": 4}, ["a", "b", "c"])
{'a': 1, 'b': 2, 'c': 3}
"""
def prune(d, keys):
"""Return a copy of D which only contains key/value pairs
whose keys are also in KEYS.
>>> prune({"a": 1, "b": 2, "c": 3, "d": 4}, ["a", "b", "c"])
{'a': 1, 'b': 2, 'c': 3}
"""
return {k: d[k] for k in keys}
def index(keys, values, match):
"""Return a dictionary from keys k to a list of values v for which
match(k, v) is a true value.
>>> index([7, 9, 11], range(30, 50), lambda k, v: v % k == 0)
{7: [35, 42, 49], 9: [36, 45], 11: [33, 44]}
"""
def index(keys, values, match):
"""Return a dictionary from keys k to a list of values v for which
match(k, v) is a true value.
>>> index([7, 9, 11], range(30, 50), lambda k, v: v % k == 0)
{7: [35, 42, 49], 9: [36, 45], 11: [33, 44]}
"""
return {k: [v for v in values if match(k, v)] for k in keys}
Many useful way to combine lists and dicts:
Lists of lists  [ [1, 2], [3, 4] ] 
Dicts of dicts  {"name": "Brazilian Breads", "location": {"lat": 37.8, "lng": 122}} 
Dicts of lists  {"heights": [89, 97], "ages": [6, 8]} 
Lists of dicts  [{"title": "Ponyo", "year": 2009}, {"title": "Totoro", "year": 1993}] 
Slicing a list creates a new list with a subsequence of the original list.
letters = ["A", "B", "C", "D", "E", "F"]
# 0 1 2 3 4 5
sublist1 = letters[1:] # ['B', 'C', 'D', 'E', 'F']
sublist2 = letters[1:4] # ['B', 'C', 'D']
Slicing also works for strings.
compound_word = "cortaúñas"
word1 = compound_word[:5] # "corta"
word2 = compound_word[5:] # "úñas"
Negatives indices and steps can also be specified.
Slicing a whole list copies a list:
listA = [2, 3]
listB = listA
listC = listA[:]
listA[0] = 4
listB[1] = 5
list()
creates a new list containing existing elements from any iterable:
listA = [2, 3]
listB = listA
listC = list(listA)
listA[0] = 4
listB[1] = 5
Python3 provides more ways in the copy module.
The following builtin functions work for lists, strings, dicts, and any other iterable data type.
Function  Description 

sum(iterable, start) 
Returns the sum of values in iterable , initializing sum to start

all(iterable) 
Return True if all elements of iterable are true (or if iterable is empty)

any(iterable) 
Return True if any element of iterable is true. Return False if iterable is empty.

max(iterable, key=None) 
Return the max value in iterable

min(iterable, key=None) 
Return the min value in iterable

sum([73, 89, 74, 95], 0) # 331
all([True, True, True, True]) # True
any([False, False, False, True]) # True
all([x < 5 for x in range(5)]) # True
perfect_square = lambda x: x == round(x ** 0.5) ** 2
any([perfect_square(x) for x in range(50, 60)]) # False
max([73, 89, 74, 95]) # 95
max(["C+", "B+", "C", "A"]) # C+
max(range(10)) # 9
A key function can decide how to compare each value:
coords = [ [37, 144], [22, 115], [56, 163] ]
max(coords, key=lambda coord: coord[0]) # [56, 163]
min(coords, key=lambda coord: coord[0]) # [22, 115]
gymnasts = [ ["Brittany", 9.15, 9.4, 9.3, 9.2],
["Lea", 9, 8.8, 9.1, 9.5],
["Maya", 9.2, 8.7, 9.2, 8.8] ]
min(gymnasts, key=lambda scores: min(scores[1:])) # ["Maya", ...]
max(gymnasts, key=lambda scores: sum(scores[1:], 0)) # ["Brittany", ...]
If a recursive function needs to keep track of more state than the arguments of the original function, you may need a helper function.
def fUnKyCaSe(text):
"""
>>> fUnKyCaSe("wats up")
'wAtS Up'
"""
def toggle_case(letter, should_up_case):
return letter.upper() if should_up_case else letter.lower()
def up_down(text, should_up_case):
if len(text) == 1:
return toggle_case(text, should_up_case)
else:
return toggle_case(text[0], should_up_case) + \
up_down(text[1:], not should_up_case)
return up_down(text, False)
Let's code this up recursively:
def sum_nums(nums):
"""Returns the sum of the numbers in NUMS.
>>> sum_nums([6, 24, 1984])
2014
>>> sum_nums([32, 0, 32])
0
"""
Docstrings typically would not specify whether an approach was recursive or iterative, since that is an implementation detail.
However, we'll make it clear in assignments and exam questions.
def sum_nums(nums):
"""Returns the sum of the numbers in NUMS.
>>> sum_nums([6, 24, 1984])
2014
>>> sum_nums([32, 0, 32])
0
"""
if nums == []:
return 0
else:
return nums[0] + sum_nums( nums[1:] )
When recursively processing lists, the base case is often the empty list and the recursive case is often allbutthefirst items.
def reverse(s):
"""Returns a string with the letters of S
in the inverse order.
>>> reverse('ward')
'draw'
"""
Breaking it down into subproblems:
reverse("ward") = reverse("ard") + "w"
reverse("ard") = reverse("rd") + "a"
reverse("rd") = reverse("d") + "r"
reverse("d") = "d"
def reverse(s):
"""Returns a string with the letters of S
in the inverse order.
>>> reverse('ward')
'draw'
"""
if len(s) == 1:
return s
else:
return reverse(s[1:]) + s[0]
When recursively processing strings, the base case is typically an empty string or singlecharacter string, and the recursive case is often allbutthefirst characters.
def reverse(n):
"""Returns N with the digits reversed.
>>> reverse_digits(123)
321
"""
Data type  Base case condition  Current item  Recursive case argument 

Numbers  == 0 == 1
 n
 n  1

Numbers (Digits)  == 0
< 10
 n % 10
 n // 10

Lists  == [] len(L) == 0
 L[0] L[1]
 L[1:] L[:1]

Strings  == '' len(S) == 1
 S[0]
 S[1:] S[:1]

Lists are represented as a row of indexlabeled adjacent boxes, one per element.
pair = [1, 2]
Each box either contains a primitive value or points to a compound value.
matrix = [ [1, 2, 0, 4], [0, 1, 3, 1], [0, 0, 1, 8] ]
A very nested list:
worst_list = [ [1, 2],
[],
[ [3, False, None], [4, lambda: 5]]]
Sea Level Rise, by Douwe Osinga: Visualize sea levels and population density on interactive maps.
Technologies used: Python (notebook) with PIL/numpy/Rasterio, HTML/CSS/JS with PanZoom
(Github repository)