Appendix B — Self Study Session - Basics
This lecture consists of several self study sessions!
In these sections you are supposed to work on the given topics on your own and in your own time. We will try to provide helpful references for books and online material that can help you but you are not limited to these materials.
In order to get an idea on how much you understand of the material we provide exercises.
In this section we are mainly concerned with the basics of Python, nevertheless you are expected to use git and pdm to solve the problems at hand.
Once you are familiar with how Python handles these topics you will be able to answer questions like:
- What is a variable?
- What is the scope of a variable?
- What is the type of a variable?
- How can I change the type of a variable?
- Is Python typed?
- Does talking about casting make sense?
- What is the difference between assignment and copy?
- What happens to objects that are no longer referenced by any variable?
- Is Python using call by value or call by reference?
- What is the signature of a function?
- What are optional arguments?
- Can I figure out or define for function arguments some basic properties?
- etc.
This topics are covered in the following resources (given in no particular order):
- McKinney (2022) Online, Section 2 and 3
- Matthes (2023) Section 2 to 8
- Vasiliev (2022) Chapter 2
- MCI Lecture notes of Julian Huber and Matthias Panny Online, Section 1 (German)
- MCI Lecture notes of Julian Huber Online, Section 1.2; (Access code is provided in Sakai)
- Overview article on type hinting dagster.io
- Type hints at docs.python.org
- Type hints cheat sheet form the docs of
mypyOnline
Exercises
Exercise B.1 (Indent is important in Python) Explain the outputs of the following code snippets, (compare Matthes 2023, chap. 4):
band_members = ["Peter", "Bjorn", "John"]
for member in band_members:
print(f"{member} played great in this song.")
print(f"I can not wait to hear {member} play in the next song.")Peter played great in this song.
Bjorn played great in this song.
John played great in this song.
I can not wait to hear John play in the next song.
band_members = ["Peter", "Bjorn", "John"]
for member in band_members:
print(f"{member} played great in this song.")
print(f"I can not wait to hear {member} play in the next song.")
print(f"I can not wait to hear all of you at the next gig.")Peter played great in this song.
I can not wait to hear Peter play in the next song.
I can not wait to hear all of you at the next gig.
Bjorn played great in this song.
I can not wait to hear Bjorn play in the next song.
I can not wait to hear all of you at the next gig.
John played great in this song.
I can not wait to hear John play in the next song.
I can not wait to hear all of you at the next gig.
band_members = ["Peter", "Bjorn", "John"]
for member in band_members:
print(f"{member} played great in this song.")
print(f"I can not wait to hear {member} play in the next song.")
print(f"I can not wait to hear all of you at the next gig.")Peter played great in this song.
I can not wait to hear Peter play in the next song.
Bjorn played great in this song.
I can not wait to hear Bjorn play in the next song.
John played great in this song.
I can not wait to hear John play in the next song.
I can not wait to hear all of you at the next gig.
Exercise B.2 (Lists, conditionals and loops) For two given lists list1 and list2 of integers with equal length define the following new lists:
list_zipwhich combines the two lists to a single list like a zip. So start with the first element oflist1, followed by the first element oflist2, than the second elements until all elements of the lists are combined.list_oddwhich contains only the odd integers oflist1, followed by the odd integers oflist2.list_zip_reversewhich combines the elements of the lists like forlist_zipbut starts at the last element oflist1.
Example:
For list1 = [1, 2, 3, 4, 5] and list2 = [11, 12, 13, 14, 15], we get
list_zip = [1, 11, 2, 12, 3, 13, 4, 14, 5, 15]list_odd = [1, 3, 5, 11, 13, 15]list_zip_reverse = [5, 15, 4, 14, 3, 13, 2, 12, 1, 11]
Exercise B.3 (Fizz Buzz) Write a program that prints the integers from 1 to 100 (inclusive). If, however, the number is a multiple of three then print Fizz instead, and if the number is a multiple of five then print Buzz.
If multiple conditions hold true then all replacements should be printed, for example 15 should print FizzBuzz.
Exercise B.4 (Difference between assignment, copy and deep copy) Have a look at the module copy and the functions copy, deepcopy as well as the standard assignment operator =.
Run the following code and explain its output:
import copy
list1 = [[1, 2, 3], [4, 5, 6], ["a", "b", "c"], 2]
list2 = list1
list3 = copy.copy(list1)
list4 = copy.deepcopy(list1)
print("List # \tID\tEntries")
print("1\t", id(list1), "\t", list1)
print("2\t", id(list2), "\t", list2)
print("3\t", id(list3), "\t", list3)
print("4\t", id(list4), "\t", list4)
list1[3] = -2
print("List # \tID\tEntries")
print("1\t", id(list1), "\t", list1)
print("2\t", id(list2), "\t", list2)
print("3\t", id(list3), "\t", list3)
print("4\t", id(list4), "\t", list4)
list2[2][2] = 9
print("List # \tID\tEntries")
print("1\t", id(list1), "\t", list1)
print("2\t", id(list2), "\t", list2)
print("3\t", id(list3), "\t", list3)
print("4\t", id(list4), "\t", list4)
list1.append([0, 8, 15])
print("List # \tID\tEntries")
print("1\t", id(list1), "\t", list1)
print("2\t", id(list2), "\t", list2)
print("3\t", id(list3), "\t", list3)
print("4\t", id(list4), "\t", list4)List # ID Entries
1 139935949860224 [[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], 2]
2 139935949860224 [[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], 2]
3 139935949859712 [[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], 2]
4 139935949859200 [[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], 2]
List # ID Entries
1 139935949860224 [[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], -2]
2 139935949860224 [[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], -2]
3 139935949859712 [[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], 2]
4 139935949859200 [[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], 2]
List # ID Entries
1 139935949860224 [[1, 2, 3], [4, 5, 6], ['a', 'b', 9], -2]
2 139935949860224 [[1, 2, 3], [4, 5, 6], ['a', 'b', 9], -2]
3 139935949859712 [[1, 2, 3], [4, 5, 6], ['a', 'b', 9], 2]
4 139935949859200 [[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], 2]
List # ID Entries
1 139935949860224 [[1, 2, 3], [4, 5, 6], ['a', 'b', 9], -2, [0, 8, 15]]
2 139935949860224 [[1, 2, 3], [4, 5, 6], ['a', 'b', 9], -2, [0, 8, 15]]
3 139935949859712 [[1, 2, 3], [4, 5, 6], ['a', 'b', 9], 2]
4 139935949859200 [[1, 2, 3], [4, 5, 6], ['a', 'b', 'c'], 2]
Hint: The function id returns the identity of an object. It is guaranteed to be unique and constant for every object as long as it exists in memory.
Exercise B.5 (Monte Carlo simulations with random numbers, functions, conditionals and loops) A circle with radius \(r\) has an area of \[A_{circle} = \pi r^2\] and the square that encases it \[A_{square} = 4 r^2.\]
The ratio between the area of the circle and the area of the square is \[ \frac{A_{circle}}{A_{square}} = \frac{\pi r^2}{4 r^2} = \frac{\pi}{4} \] and therefore we can define \(\pi\) as \[ \pi = 4\frac{A_{circle}}{A_{square}}. \] The same is true if we just take the first quadrant, so \(\frac14\) of the square as well as the circle. This simplification will make the code more compact and faster.
The algorithm therefore becomes:
- For a given number \(N\) of uniformly scattered points in the quadrant, determine if these points are in the circle (distance less than 1) or not. We call the number of points in the circle \(M\).
- Estimate \(\pi\) by computing \[ \pi \approx 4 \frac{M}{N}. \tag{B.1}\]
To write this in Python follow these steps:
- Search for a module that allows to generate random values in python.
- Define a function
def in_unit_circle(N)that computes and returns \(M\) from the function input \(N\), which is a single positive integer. Hint: You can interpret two numbers between \(0\) and \(1\) as cartesian coordinates of a point and the squared sum of them will tell you the distance of this point from the origin. - Define a function
def estimate_pi(N)that computes and returns the estimation of \(\pi\) with Equation B.1. - Search for a module that provides the exact value of \(\pi\) and write a function
def get_accuracy(N)that returns the absolute difference between the above function and \(\pi\). - Test your function with different values of \(N\). Hint: \(N\) needs to be quite large to have multiple digits of \(\pi\) correct.
Exercise B.6 (Type hinting) For the functions estimate_pi and in_unit_circle in Exercise B.5 provide type hints to suggest only integers are allowed.
How can you give a further hint that the integer is always positive?
Is the type enforced during runtime?
Exercise B.7 (Functions can have optional arguments) Let us loot at the function
Make Hi the default value for
greeting.Try calling the function as
greet(person="Peter", greeting="Hi")andgreet(greeting="Hi", person="Peter")and explain the result.Not all default values are a good choice, explain the following output
Change the code sucht that the output is
['apple'] ['banana']
Exercise B.8 (Functions can be arguments) Provide a version of the function estimate_pi(N) from Exercise B.5 that has a second argument that specifies the function to call e.g. in_unit_circle.
Provide type hints for the new function.
Note: We will come back to this example later where this will be of use.
Exercise B.9 (Recursion with Fibonacci) Create a function that computes the \(n\)th Fibonacci number with recursion, i.e. a function calling itself. Here is the sequence:
\[ x_0 = 0,\quad x_1 = 1,\quad x_n = x_{n-1} + x_{n-2},\quad n\geq 2. \] The first couple of elements are: \(0\), \(1\), \(1\), \(2\), \(3\), \(5\), \(8\), \(13\), \(21\), \(34\), \(55\), \(89\), \(144\), \(233\), \(377\), \(610\), \(\ldots\)
Exercise B.10 (Working with dictionaries) Compute the arabic number from a roman numeral, for positive integers from \(1\) to \(3999\). In order to do so use the dict as provided below, if you see fit you may change or add entries:
roman = {I:1, IV: 4, V: 5, IX: 9, X: 10, XL: 40,
L: 50, XC: 90, C: 100, CD: 400, D: 500,
CM:900, M: 1000}Examples
| Roman | Arabic |
|---|---|
| MMMDCCXXIV | 3724 |
| MXCIV | 1094 |
| VIII | 8 |
Exercise B.11 (Loop with key, value pair)
Take the dictionary of Exercise B.10 and write a loop that walks through all keys and values such that both are extracted directly in the loop.
We have seen the for loop for lists, sometimes it is helpful to still get the index of the list in addition to the value, write a code snippet that produces the following output for the list
["first", "second", "third"]index = 0, value = 'first' index = 1, value = 'second' index = 2, value = 'third'
Exercise B.12 (Set, List and Dictionary Comprehensions)
Transform a list of tuples into a list of numbers using (nested) list comprehension, i.e. the list
flatshould be created and filled in one call from the content oflist_of_sets.Is it still working if we include a set with a single entry?
What happens when we indicate that it is supposed to be a set clearly?
What happens if we have lists instead of sets?
Split a sentence give as string into a list of words (ignore
,,.for now).From this list of words, get a set (therefore unique) lengths of these words, i.e.
spy -> 3. Hint: you might want to look into the functionmap.Combine everything to get from a sentence a dictionary with length of word as key and a set of words as value. Test it with a couple of different sentences.
Can you reduce this into dictionary comprehension , i.e. create the dictionary from scratch in one go.