Ran Wei/CS Series/03
中文
Computer Science Fundamentals — Ran Wei

Module 03: Programming foundations

Write a small catalogue program and learn how values, control flow, functions and errors shape its behaviour.

≈ 5 hours4 sessions2 labs8 exercises6 quiz questions

By the end you can

  • Trace assignments and branches.
  • Use lists and dictionaries to represent records.
  • Separate logic from input/output.
  • Explain aliasing and mutation.
  • Reproduce and diagnose errors.

Before you start

Recommended modules: 01, 02.

Use a text editor and terminal. Run a .py file; never name it after a standard-library module such as argparse.py.

Contents

Study plan

5 hours

Four 75-minute sessions including practice. Allow longer for extensions or unfamiliar prerequisites. Progress is saved locally and shared between language editions.

Session 175 min
Concepts and worked examples
Session 375 min
Apply and extend
1

Values, names and expressions

A variable name refers to a value. Assignment binds a name; it is not an equation that remains true forever. After x=3; y=x; x=4, y is still 3. Expressions compute values: + adds, == compares, and and/or combine conditions. Types determine which operations make sense; '3'+ '4' concatenates text, while 3+4 adds integers. Convert external text deliberately and handle conversion errors rather than hoping the type is correct.

Check your understanding

What is y after the assignments above?

Worked solution

3; later rebinding x does not rebind y.

2

Selection and repetition

if selects a branch; for iterates over a collection; while repeats while its condition is true. Python uses indentation to group statements. An empty collection produces zero for iterations. A while loop needs a progress argument: while count<3 with count+=1 finishes, but forgetting the increment does not. break leaves a loop, continue advances to its next iteration, and return leaves a function. Use a trace table to distinguish these boundaries.

Check your understanding

What happens if the increment in a true while loop is omitted?

Worked solution

Without another exit or state change, it never terminates.

3

Collections and mutation

A list gives ordered items; a dictionary maps keys to values. A book can be {'id':1,'title':'Dune'}. Names can refer to the same mutable object: b=a does not copy a list, so b.append changes the object seen through a. a.copy creates a new outer list, but nested records are still shared. Decide whether a function mutates an argument or returns new data, and document that contract. Avoid changing a list's length while traversing it; construct a filtered result instead.

Check your understanding

Does copying a list copy every nested dictionary?

Worked solution

A shallow copy copies only the outer container.

4

Functions and interfaces

A function has parameters, a body and a result. Local names keep temporary state within a call. Return a result so callers can use it; print produces output but is not a substitute for returning data. Put catalogue search in a function, and let a separate main function parse command-line arguments and print results. This makes the same logic usable from a terminal, tests or a future web server. An if __name__ == '__main__' guard runs the interface when executed directly without running it on import.

Check your understanding

Why return records rather than print them inside search?

Worked solution

Different callers can format, test or transmit the same result.

5

Errors and debugging

Syntax errors prevent parsing; runtime exceptions report a failed operation; logic errors produce an incorrect result without necessarily raising anything. Read a traceback from the failing operation back to its caller. Reproduce with the smallest input, state the expected result, inspect intermediate values, then fix the cause. Catch a specific exception only where you can respond meaningfully. Treat invalid user input as a boundary concern; assertions check programmer assumptions and can be disabled, so they are not input validation.

Check your understanding

Should assert validate a user-supplied price?

Worked solution

No. Explicitly reject invalid input; assertions may be disabled.

6

Common misconceptions

  • A shallow copy does not isolate nested mutable objects.
  • Catching every exception and continuing can conceal corrupted state.
7

Lab setup

Download each script and run it in a terminal with Python 3.11 or later: python m03_catalogue.py. On Windows, py -3 is an alternative; on some systems use python3. The labs use only the standard library. Predict the result before running, then complete the variations. Run without -O so assertions remain enabled. Outputs below were captured by the builder. Code and output are identical in both language editions.

8

Lab 1 — A command-line catalogue

Run the default search, then pass FOUNDATION as a command-line argument. The list comprehension constructs matches without changing the input.

Download m03_catalogue.py

"""Separate reusable catalogue logic from a command-line interface."""
import argparse

def find_titles(books, query):
    query = query.strip().casefold()
    if not query:
        raise ValueError("query must not be blank")
    return [book for book in books if query in book["title"].casefold()]

def main():
    parser = argparse.ArgumentParser(description="Search a small catalogue")
    parser.add_argument("query", nargs="?", default="dune")
    args = parser.parse_args()
    books = [{"id": 1, "title": "Dune"}, {"id": 2, "title": "Foundation"}]
    for book in find_titles(books, args.query):
        print(f'{book["id"]}: {book["title"]}')
    assert find_titles(books, "FOUND") == [books[1]]
    assert find_titles(books, "missing") == []

if __name__ == "__main__":
    main()
Captured output
1: Dune
  1. Search for an absent title.
  2. Pass a quoted blank query.
  3. Add an author field and write a separate author-search function.
Worked solution

Absent prints no records. Blank input raises ValueError because an empty substring would otherwise match everything. Author search can use the same normalisation but must read book['author']; keep its validation separate from the CLI.

9

Lab 2 — Observe state and copies

Predict the two lists after every statement. The + expression returns a new list; append mutates an existing list.

Download m03_state.py

"""Observe aliasing, copies, function return values and validation."""
def add_book(books, title):
    clean = title.strip()
    if not clean:
        raise ValueError("blank title")
    return books + [clean]

original = ["Dune"]
alias = original
alias.append("Foundation")
print("after alias append:", original)
updated = add_book(original, "  Solaris  ")
print("original:", original, "updated:", updated)
assert original == ["Dune", "Foundation"]
assert updated == ["Dune", "Foundation", "Solaris"]
try:
    add_book(original, "   ")
except ValueError:
    print("blank title rejected")
else:
    raise AssertionError("must reject blank input")
Captured output
after alias append: ['Dune', 'Foundation']
original: ['Dune', 'Foundation'] updated: ['Dune', 'Foundation', 'Solaris']
blank title rejected
  1. Replace alias=original with original.copy().
  2. Make add_book mutate its argument; update its contract and tests.
  3. Explain why validation runs before the update.
Worked solution

With a copy, appending Foundation leaves original as [Dune]. A mutating version could use books.append(clean) and return None, but its tests must now expect the original to change. Validate first to avoid partially applying invalid requests.

10

Exercises with worked solutions

Try before opening the solution. ★ applies an idea; ★★ combines ideas; ★★★ asks for design or proof.

Exercise 1 — Assignment★

Trace a=2; b=a; a=a+1.

Worked solution

a=3, b=2. The final assignment rebinds only a.

Exercise 2 — Branch boundary★

For ages 17,18,19, evaluate age>=18.

Worked solution

False, True, True. Testing the boundary distinguishes > from >=.

Exercise 3 — Loop total★★

Trace total=0 then add each value in [2,4,6].

Worked solution

States after additions: 2,6,12. An empty list leaves total at zero.

Exercise 4 — Aliasing★★

After b=a; b.append('B'), why does a change?

Worked solution

Both names refer to one list. Rebinding b to a new list would be different from mutating that shared list.

Exercise 5 — Return versus print★★

A function prints 7 but has no return. What value does its caller receive?

Worked solution

None. Printing is a side effect, not a returned value.

Exercise 6 — Blank query★★★

Why validate after strip rather than only checking the original string?

Worked solution

A string of spaces is nonempty before strip but semantically blank afterwards. Normalise first, then validate the value the function will actually use.

Exercise 7 — Pure interface★★★

Design a function that filters affordable books without printing or mutation.

Worked solution

Accept books and maximum integer price_cents; validate a nonnegative limit, return [b for b in books if b['price_cents']<=limit]. State that returned dictionaries remain shared unless copied.

Exercise 8 — Debugging strategy★★

Search unexpectedly matches all books. Give a minimal investigation.

Worked solution

Try one book and a blank query; inspect the normalised query. The empty substring belongs to every string. Add boundary validation and a regression case.

11

Self-check quiz

Choose an answer for feedback; reset to retry. A text answer key is available without JavaScript.

1

What does = do?

2

Which exits a function?

3

What is a dictionary?

4

Does b=a copy a list?

5

No explicit return gives what?

6

Best use of a specific exception handler?

Answer key
  1. A — Use == for equality.
  2. B — return supplies a result and ends the call.
  3. C — Records can use named keys.
  4. A — It shares the reference.
  5. B — Print does not become a return.
  6. C — Preserve diagnostic information and handle expected failures.
12

Guided reading

13

Review and the next step

Explain the catalogue's input validation, list representation and return contract without looking at the code. Add one failing-input test. Module 04 introduces the mathematical language used to justify programs.

14

Key terms

TermMeaning
MutationChanging an existing object's state.
AliasingMultiple references to the same object.
ExceptionA signal interrupting normal control flow.