Fall 2026
  • Discord
  • Gradescope
  • Syllabus

On this page

  • The REPL
  • From expressions to functions
  • Doctests
  • This week’s lab

Python

HTML describes content, and CSS describes its appearance. Both are markup languages: you describe a result for the browser to render. Python is a procedural language: you give the computer a sequence of steps to run. The rest of the course uses Python to automate tasks.

For most people, Python is harder than HTML and CSS. If you have never programmed before, expect the next couple of weeks to be challenging.

Meme titled 'the two states of every programmer': a triumphant 'I am a god' next to a dog at a keyboard captioned 'I have no idea what I'm doing.'

Run code often and compare its behavior with what you expected.

The REPL

The fastest way to experiment with Python is the REPL, the interactive prompt you get by running python3 in a terminal. (VS Code has a built-in terminal under Terminal → New Terminal.) REPL stands for Read, Eval, Print, Loop: it reads a line, evaluates it, prints the result, and repeats. Its prompt is >>>. Type an expression and it shows you the value that expression computes:

>>> 17 + 25
42
>>> 2 ** 10
1024

The ** is exponentiation, so 2 ** 10 is two to the tenth. Every value has a type. Python’s two division operators return different kinds of results: / always gives a decimal, while // divides and throws away the remainder:

>>> 7 / 2
3.5
>>> 7 // 2
3

The 3.5 is a float (a number with a decimal point) and the 3 is an int (a whole number). You can ask any value its type with the type function:

>>> type(4)
<class 'int'>
>>> type(4.0)
<class 'float'>
>>> type("hi")
<class 'str'>
>>> type(True)
<class 'bool'>

str and bool are nonnumeric types. A str (string) is text in quotes; a bool (boolean) is one of the two values True or False. Strings support operations that numbers do not:

>>> "ha" * 3
'hahaha'
>>> len("automate")
8

Multiplying a string repeats it, and len reports how many characters it holds. Practice in the REPL until you can predict each result.

From expressions to functions

The REPL is for experiments; to keep work, write it in a .py file. The unit of reusable work in Python is the function: a named block of code that takes inputs and produces an output. We have already called functions (type(...) and len(...) are both functions), and now we write our own with def:

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

The def line names the function is_even and says it takes one parameter, n, a stand-in for whatever value we call it with. The indented line is the body, the steps that run when the function is called. The % operator is the modulus: it gives the remainder after division, so n % 2 is 0 exactly when n is even. The expression n % 2 == 0 compares that remainder to zero with == and evaluates to a bool. return sends that bool back to the calling code.

return and print do different jobs. return sends a value back to the surrounding program, while print displays text and returns None. Other code cannot use the displayed result as a value. Compare the two:

>>> is_even(10)
True
>>> is_even(10) and is_even(7)
False

The second example combines two returned booleans with and. Swap the return for a print and that second line breaks, because there is no value to combine.

Functions use control flow to choose between paths or repeat a step. An if statement runs its block only when a condition is true, with an optional else for the other case:

def absolute_value(n):
    if n < 0:
        return -n
    else:
        return n

A while loop repeats its block as long as a condition holds, and a for loop repeats once per item in a sequence. The built-in range creates number sequences for loops, so range(1, n + 1) counts from 1 up to n:

def factorial(n):
    result = 1
    for i in range(1, n + 1):
        result = result * i
    return result

We start an accumulator result at 1, then let i take each value from 1 to n, multiplying result by i and storing it back each time. When the loop finishes, result holds 1 * 2 * ... * n, and we return it. What would go wrong if we started result at 0 instead of 1? Try it in the REPL.

Doctests

Checking factorial by hand after every change is repetitive. A doctest automates that check and is the basis of every lab in this course.

A doctest is an example of your function’s behavior, written right into its documentation, in the exact form of a REPL session: the >>> prompt, the call, and the expected result on the next line:

def is_even(n):
    '''
    Return True if n is even and False if n is odd.

    >>> is_even(0)
    True
    >>> is_even(7)
    False
    >>> is_even(-8)
    True
    '''
    return n % 2 == 0

The triple-quoted text under the def line is a docstring, the function’s documentation. Each >>> call and its expected return value form a test that Python can check automatically. Run the file through the doctest module from your terminal:

$ python3 -m doctest example.py

When every doctest passes, the command prints nothing and returns you to the prompt. Add -v to print each test and a tally:

$ python3 -m doctest -v example.py
...
3 passed and 0 failed.
Test passed.

Suppose we wrote the incorrect expression return n % 2 == 1. The tests report:

$ python3 -m doctest example.py
**********************************************************************
File "example.py", line 5, in example.is_even
Failed example:
    is_even(0)
Expected:
    True
Got:
    False
...
***Test Failed*** 3 failures.

For every broken example it prints the exact call, the expected value (Expected: True), and the actual value (Got: False), followed by a failure count. All three examples fail here because == 1 asks the opposite question. In a lab, the tests are provided. Write each function until every Got matches every Expected and the command reports no failures.

The lab is a .py file full of functions with doctests and empty bodies. Fill in the bodies until the doctests pass on your machine, then push the file to GitHub. The same public doctests run automatically there and set a status badge to red or green. That badge is preliminary feedback, not the grade: submit the repository and branch through Gradescope, where instructor-owned tests check the required behavior. You may keep fixing, pushing, and resubmitting until all required tests pass.

This week’s lab

This week’s Doctests lab contains about thirty short functions that practice these techniques. Do them yourself even though an LLM could write them in seconds; later problems assume that you have practiced the underlying steps.