You’ll be able to:
len, append, insert, remove, pop, sort, …in, index, countYou’ll be able to:
You’ll be able to:
You’ll be able to:
global is neededlambdas*args and **kwargsLists and tuples
listSo far we’ve stored only single values in variables.
Python’s list allows us to store multiple values.
Create empty list
We create a list with the list() function or simply [].
Create list with content
We can create a list initialized with some elements.
Size of the list
Adding elements
Like strings, lists have several methods that help with their interaction.
What is +=?
It looks like a shortcut for
Lists support the + operator: the list on the right is concatenated to the list on the left.
Almost the same, but not quite: += changes the list in place, while + creates a new list. We’ll see why this matters in Mutable vs Immutable.
We can also add elements at specific positions with the .insert method.
Getting an element
List indeces are 0-based.
Slicing
We may get a slice of the list.
The second index is not included in the slice.
Slicing rule
Slicing examples
l = [1,2,3,4,5,6]
l[0:3] # returns a list with all elements starting
# on index 0 and ending on 2 -> [1,2,3]
l[0:1] # returns a list with just the 1st element -> [1]
l[1:1] # returns an empty list -> []
l[:] # returns all elements of the list -> [1,2,3,4,5,6]
l[:-2] # returns all elements except the last 2 -> [1,2,3,4]More Slicing
l = [1,2,3,4,5,6]
l[-3:-1] # all elements starting on the 3rd last position
# and finishing on the 2nd last -> [4,5]
l[-3:] # all elements from the 3rd last onwards -> [4,5,6]
l[::2] # every other element, starting on index 0 -> [1,3,5]
l[1::2] # every other element, starting on index 1 -> [2,4,6]
l[1::3] # every 3rd element, starting on index 1 -> [2,5]Even more slicing
Removing an element
The remove method deletes a given value from the list. If it exists more than once in the list, the first occurrence is removed.
If the value does not exist in the list, an error is thrown.
Concatenate 2 lists
Adds to list l all elements from temperatures.
Check existence
The in operator checks if the value on the left exists inside the data structure on the right.
Other methods
l[::-1] gives the same order as l.reverse(), but not the same effect.1
tupleSlicing (again…)
Slicing and concatenation work as in lists.
tuple <-> list
We can easily convert between lists and tuples.
Immutable objects (int, float, str, tuple) cannot be changed after creation.
Mutable objects (list, dict) can be changed in place.
The aliasing trap
Assigning a list to a new variable gives you a second name for the same object.
Lists are references, not copies. (This should be familiar to C programmers)
+= vs +
Behind the scenes…
Check identity with id()
Loops
What are they?
The while loop
They execute a set of instructions while a given condition is true:
What is being used for the condition must change, otherwise we might have an infinite loop.
Let’s sum a list of numbers:
To stop a loop, we can use the break instruction:
We can skip the rest of the current iteration with the continue instruction:
The for loop
We had to declare a variable just for increasing the position of the list element, but we also have the for loop which makes this kind of logic easier.
Actually, range() returns an iterable that goes from a number to another higher number.
We can convert this iterable to a list, but we don’t have to do it in the context of the for loop.
Lists have another property: they’re also iterables! That means we don’t even need the range function in the last example.
enumerate
What is an enumeration?
One way to solve this would be to use the range() function.
But enumerate makes life a lot easier.
enumerate receives a list and gives us a sequence of (index, value) tuples0, 1, 2, ...records[0], records[1], records[2], ...Actually, enumerate returns an iterable (like range), so we convert it to a list to see its contents.
It also can receive any iterable, not just a list.
zip
Let’s now say we have a list of patient IDs and ages and want to print them.
Using what we know, we can implement it like this.
zip receives 2 or more lists and creates a new list where each element is a tuple with the values of the original 2 lists.
zip, like enumerate, actually returns an iterable - that’s why we converted it to a list before printing.
zip can receive any iterable, not just lists.
zip can receive any number of iterables as input, e.g. zip(l1, l2, l3, ...)
When the size of the input iterables is different, zip will return an iterable with the size of the shorter input.
Dictionaries and comprehensions
dictdict) is like a key/value database.creating a dict
The types of both keys and values can be anything (that is hashable)
We can initialize a dict with many values.
We can initialize a dict from a list of 2 element tuples.
We can have nested dicts too.
Getting a value
Inserting a value
Removing a value
models.pop("NaiveBayes") # removes key "NaiveBayes" and returns its value
# -> 0.81
models.pop("XGBoost") # KeyError: 'XGBoost'
models.pop("XGBoost", -1) # tries to remove key "XGBoost" and
# returns -1 if it does not exist
del models["LogisticRegression"] # just deletes key "LogisticRegression"
del models["XGBoost"] # KeyError: 'XGBoost'Useful methods
dict and loops
Print the accuracy for each model:
listLet’s say we would like to create a list with all even numbers from 0 to 99, that are not divisible by 4.
A possible implementation would be
dictCreate a dictionary with the models that have accuracy above 90%.
Functions
*args, **kwargsHow to reuse the same logic for different things?
We can think of a function as a black box that receives inputs and gives outputs.
What functions have we seen before?
def keywordsum_2 and ( )( ) we write the names of the inputs (a.k.a. arguments) the function should receive.return is usedreturn can receive multiple values - which means the function will output multiple values
Let’s use our function.
We call a function by writing its name, followed by ( ). Inside the ( ) we give the arguments (inputs).
We call sum_2 with input x. Inside sum_2, the argument a refers to the value of x.
Passing a list
Remember aliasing? The argument is another name for the same object.
Numbers and strings are immutable, so a function cannot change them this way.
We can have local and global variables
a and b exist only inside function sum_2.
But x exists outside the function too.
x is unchanged by calling sum_2
a and b are said to be local variables, within the scope of the functionx is a global variable, because it exists outside the scope of any functionNow what?
x inside the functionx=4 inside the function creates a new local variable x with the same name as the global variable xx inside the function expects a variable named x within the scope of that functionIf we wanted to change (and not only read) the global variable, we need to declare it.
All global variables are stored inside a dictionary that can be accessed by calling globals().
What would happen if we tried to change a global variable without declaring it?
In Python, functions are just like any other object that can be passed around.
We can even attribute a function to a variable and then call the same function with the name of the new variable.
We may also pass a function as an argument to another function.
There is a shortcut for defining short and simple functions:
:, we write the expression that will be returned (no need to write return).Why is this useful? Because we can pass custom operations to other functions and apply them elsewhere.
We can also import other functions and apply them in our codebase.
We’ll see 2 particularly useful examples of using functions in this way, map and filter, in the next session.
Arguments can have default values.
Arguments with defaults must come after those without.
*args — variable positional arguments*args collects any number of positional arguments into a tuple.
**kwargs — variable keyword arguments**kwargs collects any number of keyword arguments into a dict.
*args and **kwargsPython allows annotating the types of variables, arguments and return values.
Annotations are not enforced at runtime — Python does not check them.
Why use them anyway?
mypy can catch type errors before runningUse them in function signatures when they make the code clearer.
listl = [1,2,3,4,5] # creating a list
l[1] # getting an element ->2
l.append(6) # adding value 6 -> [1,2,3,4,5,6]
l.remove(1) # removing value 1 -> [2,3,4,5,6]
l.index(3) # finding value 3 -> 1
l = l + [7,8] # appending lists -> [2,3,4,5,6,7,8]
l.extend([7,8]) # does the same thing
l.insert(0, 42) # add 42 at index 0 -> [42,2,3,4,5,6,7,8]
len(l) # size of list 8
l[0] = 24 # change value at index 0 -> [24,2,3,4,5,6,7,8]
l[2:-2] # slice the list -> [3,4,5,6]
24 in l # -> Truetuplewhileforbreak and continuerangeenumeratezipenumerate in loopszip in loopsWhat is the pattern?
Combining with unpacking!
is equivalent to
dictauthors = {
"Saramago": 87,
"Pessoa": 47,
"Camões": 56
}
authors_lst = [("Saramago", 87), ("Pessoa", 47), ("Camões", 56)]
authors = dict(authors_lst)
authors = {
"Saramago": {"died_at": 87, "first_name": "José"},
"Pessoa": {"died_at": 47, "first_name": "Fernando"},
"Camões": {"died_at": 56, "first_name": "Luís"},
}functions
return is usedvariable scope in functions
Local and global variables
first class functions
functions are also objects that can be given to variables and functions
lambda
⚠️⚠️ keep your lambdas short, simple and clear ⚠️⚠️
default arguments, *args, **kwargs
type annotations
mypy)