Python for Science

Exercises

Welcome to the first set of exercises! It's hopefully possible to complete all of these exercises using what you learned so far plus the extra information in the exercise descriptions.

In some exercises I provide skeleton code which you can copy-paste and use as basis for your solution.

For some of these exercises the math module from Python's standard library will be helpful.

math - Mathematical functions

import math

print(math.sqrt(16)) # 4.0
print(math.cos(math.pi)) # -1.0

After you import the module, which you should do at the top of the program, you can use it further down in the code.

Example exercises

Example 1: Count down

Write a for-loop that prints the numbers 15 to 0 in descending order. Documentation for range().

Example output:

15
14
.
.
.
1
0

My solution:

for i in range(15, -1, -1):
  print(i)

The documentation for range() states that it can take three parameters: start, stop and step. Since I want to loop in descending order I give -1 as the argument for the step parameter.

Example 2: Even or odd

Write a function that takes a positive integer and returns True if the integer is even, otherwise return False. Remember the % (modulo) operator which calculates the remainder after division.

Skeleton code:

def is_even(x):
    pass

print(is_even(5)) # False
print(is_even(2)) # True

My solution:

You can use the modulo operator to see if the remainder after dividing the number by 2 is equal to 0. If the remainder is 0, it means that the number can be evenly divided (no decimals) by 2, thus it must be even. If the remainder is not 0, it must be odd.

def is_even(x):
    return x % 2 == 0

print(is_even(5)) # False
print(is_even(2)) # True

The modulo operation is not the most intuitive. It can be helpful to read more about it. Wikipedia: Modulo operation.

Example 3: Quotient and remainder

Write a function that takes a number and divisor and returns the quotient and remainder of the number divided by the divisor using integer division. Both parameters should be positive integers. Return the quotient and remainder as a tuple. You are only allowed to use loops, comparison operators and subtraction.

Basically, implement a simpler version of divmod().

Tuples are a type of sequence data structure that I previously skipped: tuple documentation. A tuple consists of values separated by commas, often enclosed by parenthesis. t = (1, 3, "hello!"). The main difference between tuples and lists is that tuples are immutable (impossible to change), while lists are mutable. You can add new values to lists: [1, 2].append(3). This is not possible for tuples. The syntax is also different, tuples use parenthesis instead of square brackets.

Skeleton code:

def quotient_and_remainder(x, d):
    pass

print(quotient_and_remainder(5, 2)) # (2, 1)
print(quotient_and_remainder(2, 5)) # (0, 2)
print(quotient_and_remainder(18, 3)) # (6, 0)
print(quotient_and_remainder(18, 1)) # (18, 0)
print(quotient_and_remainder(1396612, 213)) # (6556, 184)

My solution:

def quotient_and_remainder(x, d):
    nr_of_divisions = 0

    while x >= d:
        nr_of_divisions += 1
        x -= d

    return nr_of_divisions, x

print(quotient_and_remainder(5, 2)) # (2, 1)
print(quotient_and_remainder(2, 5)) # (0, 2)
print(quotient_and_remainder(18, 3)) # (6, 0)
print(quotient_and_remainder(18, 1)) # (18, 0)
print(quotient_and_remainder(1396612, 213)) # (6556, 184)

Interesting exercise. I did some tests to compare my output compared to divmod() and fixed some issues after looking at Wikipedia (off-by-one errors again).

The function is doing something called division by repeated subtraction, which was apparently documented by Euclid more than 2000 years ago. His writings can be found in the book Elements. Neat! You can find a some more information here: Euclidean division.

Those were the example exercises. I think the last one was pretty cool.

Now it's your turn to have fun! Well, try to have fun. I think you'll notice that writing code is much harder than reading code.

Exercise 1: Basic math

Built-in functions (some are math-related): Built-in functions

Mathematical operations: Numeric Types - int, float, complex

More math functions (like rounding): math module

Calculate what's asked for in the list below using Python. You can choose if you want to write the code in a file or directly in the Python shell (terminal).

  1. a) 21 modulo 5
  2. b) 4 raised to the power of 3
  3. c) Square root of 30
  4. d) 31 times 5 plus 85 divided by 17
  5. e) 1.7 rounded to the nearest integer
  6. f) 1.9 rounded down (i.e. rounded to 1)
  7. g) Area of a rectangle with width 9 and height 3
  8. h) Area of a circle with radius 6
  9. i) Cosine of pi
  10. j) The hypotenuse c of a right triangle where a = 3 and b = 4

Finally, implement a function that calculates and returns the hypothenuse of a right triangle. The function should take two parameters representing the shorter sides of the triangle.

Skeleton code:

def hypotenuse(a, b):
    pass

print(hypothenuse(1, 1)) # 1.4142
print(hypothenuse(3, 4)) # 5
print(hypothenuse(16, 198)) # 198.65

Good luck!

Exercise 2: Strings

Strings documentation: Text Sequence Type - str

Common sequence functionality also supported by strings: Common Sequence Operations

String formatting (for historical reasons, there are now many ways to format strings, I tend to prefer f-strings): Tutorial - Input and Output

Strings documentation from the tutorial: Tutorial - Strings

In the "Common Sequence Operations" link you can find something called slicing. Slicing is a neat way of taking out specific parts of a string (or any sequence). It's like an extension of indexing. The syntax for slicing looks like s[start:stop:step], where s is a sequence.

"abc"[0] gets "a" from the string because "a" is located at index 0. "abc"[0:2] gets the substring "ab" from "abc" (the start index 0 is inclusive, the end index 2 is not inclusive). "abc"[0:3] gets the entire string "abc" from "abc". Another feature is that you can include the colon but not the end index, which implicitly means "go all the way to the end". "abc"[0:] == "abc".

In Python you can index from the reverse as well. "abc"[-1] == "c". You can also get the reverse string by slicing with a negative 1 step. "abc"[::-1] == "cba.

Do what's asked for in the list below using Python. You can choose if you want to write the code in a file or directly in the Python shell (terminal).

  1. a) Get the substring "year" from "Happy new year!"
  2. b) Get the reverse of "Happy new year!"
  3. c) Get the length of "Happy new year!"
  4. d) Count the number of "e"s in the string "Happy new year!"
  5. e) Count the number of "ww"s in the string "www"
  6. f) Find the index of "py" in the string "Happy new year!"
  7. g) See if "py" is a substring of "Happy new year!" (do not use find())

Implement a function that checks if a string is a palindrome. It should take an input string as parameter and return a boolean as result. The function should be case insensitive, "Anna" should be a palindrome. To make it more challenging you can make the function strip away non-alphabetical characters so that "Ann a." is also a palindrome.

Skeleton code:

def is_palindrome(s):
    pass

print(is_palindrome("hannah")) # True
print(is_palindrome("Hannah")) # True
print(is_palindrome("bilbo")) # False
print(is_palindrome("A nut for a jar of tuna.")) # True (if you strip away non alphabetical characters)

Good luck!

Exercise 3: Grain size

Implement a function that takes particle_size as parameter and returns the name of the soil separate according to the WRB Classification: Wikipedia - Soil texture - Soil separates. The WRB table data is repeated below:

Name Diameter (mm)
Clay less than 0.002
Silt 0.002 - 0.063
Very fine sand 0.063 - 0.125
Fine sand 0.125 - 0.20
Medium sand 0.20 - 0.63
Coarse sand 0.63 - 1.125
Very coarse sand 1.25 - 2.00

Skeleton code:

def get_classification(particle_size):
      pass

my_particles = [0.0001, 0.0035, 0.07, 0.170, 0.3, 1.02, 1.6]
for p in my_particles:
    print(get_classification(p))

Example output:

clay
silt
very fine sand
fine sand
medium sand
coarse sand
very coarse sand

At first glance the specification looks quite clear. There's even a table! But when you start to think about it in a larger context you will notice that some things are actually unclear.

These are some of my own observations regarding this task:

  • The example output indicates the function should return lowercase strings with spaces.
  • It isn't specified how out-of-range (> 2 mm) or invalid data (like negative values or non-numbers) should be handled.
  • There is currently no docstring for the function. How will anyone know the function expects values in mm?

Feel free interpret the specification in your own way. You can modify the skeleton code as much as you like. As long as you end up with a function (or functions + helpful constants) that does approximately what the exercise asks for you should be happy. Good luck and don't forget that you can search for information on the internet!

Exercise 4: FizzBuzz

FizzBuzz is a common programming exercise given as an interview question. It is used to filter out non-programmers.

Write a program that prints the numbers from 1 to 100. But for multiples of three print the number and "Fizz" and for the multiples of five print the number and "Buzz". For numbers which are multiples of both three and five, print the number and "FizzBuzz".

Example output:

1
2
3 Fizz
4
5 Buzz
6 Fizz
7
8
9
10 Buzz
11
12 Fizz
13
14
15 FizzBuzz
16
...

Put the solution in a file called fizzbuzz.py and email the file to Microsoft.