Note 3: Tracing and Types

Reading: TODO

Notes

Code Tracing

We’ll now look at an example of how to execute a program “by hand.”” That is, how to trace a program’s execution by methodically following its execution step-by-step. At first this will appear tedious, but it is critical to a firm understanding of how programs execute, and eventually to writing your own programs.

For our example, let’s look at this very simple program:

print(1)                   

for j in range(2, 5):      
    for i in range(j):     
        print(j, end='')
    print()

Let’s now dive into the longer version, just for the sake of understanding.

To make best use of this, open this same page in another browser, and have the program side-by-side, as you read what’s below.

Ready? Let’s trace through:

tracing

  • Right at the start, the first line is print(1). This prints out 1, and moves to the next line.

tracing

  • Initially j = 2 at the start of the outer for loop:

tracing

  • Since j is 2, it’s within the range, and we enter the outer for loop.
    • Now we encounter the inner for loop, where i is set to 0
    • Note: when range has only one number specified, it’s understood to be the upper limit. The upper limit is the current value of j, which is 2.

tracing

  • Inside the inner loop, we execute print(1) ,which, because j is now 2, will print 2.

tracing

  • We’re at the end of the inner loop, so now i increments to 1:

tracing

  • So now inside the inner loop, we print 2 again.

tracing

The output currently looks like:

1
22
  • Then, at the end of the inner for loop, we return to the top where i increments to 2. Since i is at the limit, we exit the inner for loop.

  • Notice: the inner loop iterated twice. Next, we go past the inner loop to print() , which goes to the beginning of the next line.

tracing

tracing

The print statement here completes the first iteration of the outer loop, after which we go to the top of the outer loop and increment j.

tracing

Execution now enters the outer loop with j set to 3.

  • Now we encounter the inner for loop, where i is set to 0 The upper limit is the current value of j , which is 3.

tracing

  • So, the inner loop executes three times, with i first set to 0, then to 1, then to 2.
  • This will result in printing three 3’s. When i becomes 3, it hits the inner loop’s limit and proceeds to the print() that follows. The output so far is:
1
22
333

This completes the iterations of the inner loop with the outer loop j set to 3. Next, j becomes 4

tracing

  • The inner loop starts with i set to 0.
  • Each time through i increments.
  • Until i hits the limit j (which is 4 now).
  • This results in four 4’s being printed in a line. Then we come out of the inner loop and execute print() , which goes to the next line. The output so far is
1
22
333
4444

Finally at the end of the outer loop, j becomes 5 and hits the limit of the outer loop

tracing

Yes, that was long. But doing this many times will help you understand how to read programs. Later, you will become good at this and will, with a quick glance at the inner loop, say “This prints 2 twice in the first iteration of the outer loop.”

Types

Python has support for type hints that explicitly call out the type of variables.

Compare “vanilla” Python:

x = 2
y = 3.2
z = x + y
print(z)
5.2

With type-hinted Python:

x:int = 2
y:float = 3.2
z:float = x + y
print(z)
5.2

The functionality is the same, but the type hints allow the programmer to explicitly define what type each variable is, which can aid in debugging and validating the correct functionality of the program.

For variables, the syntax is straightforward: during assignment, use a colon after the variable name, followed by the type, before the assignment operator.

Type hints are especially useful with functions:

def f(x:int) -> float:
    return x / 2

print(f(4))
2.0

The function f above takes one integer argument, and returns a float. The “arrow” -> is used in function definitions to specify the return type.

mypy

A utility called mypy can check for type issues in type-hinted Python. Add mypy to any Python project using:

uv add mypy

Try validating this Python program (it has errors):

errors.py
def f(x: int, y: float) -> str:
    z:int = x + y
    return str(z)

a: int = 2.0
b: int = f(a, 2*a)

Validate it by running:

mypy errors.py

Now try to fix the errors! Note that the default mypy behavior does not require type hints, it only checks for errors for the type hints that have been used.

Practice

Practice Problem 3.1

Practice Problem 3.1

Rewrite the multiple_digits function from the notes, using a different sequence of if, elif and else statements (with different conditions).

Practice Problem 3.2

Practice Problem 3.2

Rewrite the smaller function from the notes. Keep the existing functionality, but add a check to see if the input arguments are numbers (ints or floats). If either argument isn’t a number, return False.

Practice Problem 3.3

Practice Problem 3.3

Write a function even_smaller that takes three integer arguments and returns the smallest of the three. You can assume that the arguments are all integers.

Practice Problem 3.4

Practice Problem 3.4

Write a function n_times that takes two arguments. The first is an integer, the second is a string. If the integer is greater than 0, return the string “multiplied” by the integer:

  • n_times(1, "ok") returns string "ok"
  • n_times(3, "times") returns string "timestimestimes"

If the integer is less than 1, return an empty string "".

Recall: using the * operator between a string and an integer will repeat the string in the manner desired. Try it out in the interpreter.

Practice Problem 3.5

Practice Problem 3.5

Write a function i_before_j that takes two arguments, both strings. Return a string in the format shown below, with the correct alphabetical order between the two strings:

  • i_before_j('dog', 'cat') returns string 'cat before dog'
  • i_before_j('coffee', 'supper') returns string 'coffee before supper'
  • i_before_j('practice', 'success') returns string practice before success'

Remember that > and < between strings is based on alphabetical order.

Homework

  • Homework problems should always be your individual work. Please review the collaboration policy and ask the course staff if you have questions. Remember: Put comments at the start of each problem to tell us how you worked on it.

  • Double check your file names, printed output, and return values. These need to be exact matches for you to get credit.

  • Going forward, you will need to write functions that return instead of print. Confusing these two is a common error - take care to avoid it!

Homework Problem 3.1

Homework Problem 3.1 (25 pts)

Write a function ordered_triple that takes three arguments, all numbers.

Return a string consisting of the three numbers in numerical order, smallest to largest, separated by spaces, with no trailing space:

  • ordered_triple(5, 2, 3) returns string '2 3 5'
  • ordered_triple(1, 0, 1) returns string '0 1 1'
  • ordered_triple(1, -2, -3) returns string '-3 -2 1'

Do not use built-in or library functions that sort, find minimum, or find maximum.

Submit as ordered_triple.py.

Homework Problem 3.2

Homework Problem 3.2 (25 pts)

Write a function three_or_four. It will take one argument, which will be one of these:

Threes:

  • int 3
  • float 3.0
  • str '3'
  • str 'three'

Fours:

  • int 4
  • float 4.0
  • str '4'
  • str 'four'

Return either int 3 or int 4, corresponding to the input value.

  • three_or_four('four') returns int 4
  • three_or_four(3) returns int 3

Submit as three_or_four.py

Homework Problem 3.3

Homework Problem 3.3 (25 pts)

Write a function three_digits that takes a single integer argument and returns True if the integer has exactly three digits and False otherwise.

  • three_digits(-123) returns True
  • three_digits(1001) returns False
  • three_digits(101) returns True
  • three_digits(-20) returns False
  • three_digits(-300) returns True

Submit as three_digits.py.

Homework Problem 3.4

Homework Problem 3.4 (25 pts)

Write a function seq_omit that takes three arguments, each a positive integer. Return a string consisting of sequential integers, starting at the smallest argument, skipping the middle-valued argument, and ending with the largest argument. The arguments will all be different values.

Examples:

  • seq_omit(1, 3, 6) returns string '1 2 4 5 6'
  • seq_omit(3, 1, 6) returns string '1 2 4 5 6'
  • seq_omit(5, 4, 2) returns string '2 3 5'
  • seq_omit(2, 1, 4) returns string '1 3 4'

Do not use built-in or library functions that sort, find minimum, or find maximum.

Submit as seq_omit.py.