Python Fundamentals¶
By the end of this lesson, students will be able to:
- Apply while loops to iterate until reaching a desired program condition.
- Write docstrings and doctests to describe and test functions in Python.
- Explain a bug by using the debugger to pause and inspect variable state.
While loops¶
A while
loop has a condition and a body. Each iteration executes the indented code only if the condition is True
, otherwise the loop ends.
x = 1
while x < 100:
print(x)
x = x * 2
print("After loop: x =", x)
1 2 4 8 16 32 64 After loop: x = 128
Practice: Countdown¶
Use a while
loop to write a function countdown
that takes a starting whole number of seconds and counts down to 0 (inclusive) decrementing by 10 each time. If the starting number of seconds is less than 0, it should instead print "Start must be non-negative!"
Here are 4 example countdown
calls (prefixed >>>
) and followed by the corresponding printed output.
>>> countdown(60)
60 second countdown
60
50
40
30
20
10
0
Done!
>>> countdown(15)
15 second countdown
15
5
Done!
>>> countdown(-4)
Start must be non-negative!
>>> countdown(0)
0 second countdown
0
Done!
def countdown(start):
"""
Prints a countdown from a whole number start to 0 (inclusive) decreasing by 10. The countdown
begins with a printed announcement for the duration and concludes with a printed announcement
"Done!" If the start is negative, only prints the message "Start must be non-negative!"
>>> countdown(60)
60 second countdown
60
50
40
30
20
10
0
Done!
>>> countdown(15)
15 second countdown
15
5
Done!
>>> countdown(-4)
Start must be non-negative!
>>> countdown(0)
0 second countdown
0
Done!
"""
if start < 0:
print("Start must be non-negative!")
else:
print(start, "second countdown")
while start >= 0:
print(start)
start -= 10
print("Done!")
Documenting and testing countdown¶
In this course, writing the program logic is only the first of several tasks. It is also important to describe and test functions for data science software development. In this course, all functions that you write must be documented in your own words, and many of them will also require additional testing.
Docstrings (documentation strings) are a Python-specific way to describe a function's behavior. A docstring is a specially-formatted multi-line string that appears directly underneath a function definition. A docstring should describe the behavior of the function, its parameters and return values, and any notable behaviors without including implementation details about the program logic.
def countdown(start):
"""
Prints a countdown from a whole number start to 0 (inclusive) decreasing by 10. The countdown
begins with a printed announcement for the duration and concludes with a printed announcement
"Done!" If the start is negative, only prints the message "Start must be non-negative!"
"""
... # Your program logic
Multi-line strings can be declared using either """
or '''
.
Doctests (documentation tests) are a Python-specific way to test a function's behavior alongside the documentation. The larger your data programs grows, the harder it is to reason about all the parts at once: by testing our functions, we can ensure that they behave as expected and communicate its use to other programmers.
Let's update your countdown
function above by copying the example docstring over and adding the 4 doctests to it shown above. Doctests are just exactly as they appear in the example above: prefixed >>>
and followed by the corresponding printed output. Once you've added your doctests, run the following cell to see how many test cases pass: a correct program will produce no output in the following cell.
import doctest
doctest.run_docstring_examples(countdown, globals())
Comparing countdown approaches¶
Earlier, we learned how to write a 60-second countdown using a for
loop. Let's compare the for
loop approach to the while
loop approach:
- From a software development or code quality perspective, why might we prefer to use a
for
loop? - From a software development or code quality perspective, why might we prefer to use a
while
loop?
Replace this text with your answer and run this cell when you are done editing.
Practice: Debugging FizzBuzz¶
A question that used to be frequently asked in software interviews is FizzBuzz:
Write a function called
fizz_buzz
that takes a numbern
and prints all the numbers from 0 ton
(exclusive) one on each line. However, for each number that is divisible by 3, it should print the wordFizz
instead of that number. For each multiple of 5, you should print the wordBuzz
instead of that number. For numbers that are multiples of both 3 and 5, you should printFizzBuzz
.
To practice debugging, documenting, and testing, let's consider this incomplete sample solution. Run the following cell to see its output and identify where it differs from the problem description.
def fizz_buzz(n):
"""
Prints the numbers from 0 to n (exclusive) on each line, with special rules for printing "Fizz",
"Buzz", or "FizzBuzz" instead of certain numbers.
>>> fizz_buzz(1)
FizzBuzz
>>> fizz_buzz(5)
FizzBuzz
1
2
Fizz
4
"""
for i in range(n):
if i % 15 == 0:
print("FizzBuzz")
elif i % 3 == 0:
print("Fizz")
elif i % 5 == 0:
print("Buzz")
else:
print(i)
fizz_buzz(20)
FizzBuzz 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19
Debugging is primarily about understanding the difference between what a program's expected behavior and its actual behavior. The fix to a bug often follows from a clear and complete explanation of why the bug occurs, so the goal of debugging is to gain more and more information about the problem until we can clearly explain the problem.
To launch the debugger, in the top right corner of the interface, look for the Enable Debugger 🐞 (beetle or bug) icon. To use the debugger, we have to add a breakpoint, which tells Python where to pause the program for inspection.
- Add a breakpoint to line 6,
print("Buzz")
. - Run the cell: the program will pause before printing the first "Buzz".
- Try ⤼ stepping over a few times before using the ▶ continue button to run until the next breakpoint (or end of the program).
- Find the point at which the program should print "FizzBuzz", but doesn't! If you went too far, go back to step 2 and re-run the cell.
Now that you have an idea about the problem, edit the fizz_buzz
function so that it produces the desired output. The staff solution adds 2 lines of code and edits 1 existing line of code.
doctest.run_docstring_examples(fizz_buzz, globals())
Practice: Mean¶
mean
is a function that takes two numbers and return their arithmetic mean (average). Write a doctest to identify and address the bug in the sample solution.
- Write a descriptive docstring in your own words.
- Write one or more doctests that pass using the sample solution: examples where the sample solution returns the correct mean value.
- Write one or more doctests that fail using the sample solution: examples where the sample solution returns the wrong mean value.
def mean(a, b):
"""
Returns the artihmetic mean (average) of the two given numbers.
>>> mean(2, 4)
3.0
>>> mean(1, 2)
1.5
"""
return (a + b) / 2
doctest.run_docstring_examples(mean, globals())
After writing your tests, fix the bug in the mean
program with the help of your testing and debugging experience.
Doctest results summary¶
The following cell runs all function definitions that include doctests. The returned TestResults
indicate how many tests were attempted, and how attempted tests failed.
doctest.testmod()
TestResults(failed=0, attempted=8)