ailiteracynepal 🇳🇵
Text size

Chapter 02 · Section II · 28 min read

Functions, loops, and code you can reread

Programs grow. Lines you would not write twice are lines you should not write twice. Functions and loops are the two tools that keep code small. Naming and indentation are what keep it readable.

In the last section you held data in lists, dictionaries, and tables. In this one you start doing things to it — without copy-pasting the same three lines six times. Two tools do most of the work: a function packages a piece of behaviour under a name; a loop repeats a piece of behaviour over a collection. Almost every program you read from this point on is some combination of those two.

A loop, simply

A loop walks through a list and runs a piece of code once per item. The simplest form:

expenses = [120, 80, 250, 90, 45]

for expense in expenses:
    print(expense)

That prints five lines, one per item. Read the shape of it carefully:

  • for expense in expenses: — for each item in the list, call it expense (you choose this name). The colon at the end starts the body.
  • The indented line below is the body of the loop. It runs once for each item, with expense taking the next value each time.
  • Indentation is not decoration. Python uses it as actual syntax. Two lines indented the same way are part of the same body. Indent inconsistently and Python will refuse to run the file.

A common pattern: keep a running total.

expenses = [120, 80, 250, 90, 45]

total = 0
for expense in expenses:
    total = total + expense

print(total)   # 585

Read line by line. total starts at zero. Each pass through the loop adds the next expense to it. After the loop finishes, total holds the sum.

A function, simply

A function is a piece of behaviour with a name. You define it once and call it as often as you like:

def total(expenses):
    running = 0
    for expense in expenses:
        running = running + expense
    return running

Read it slowly:

  • def total(expenses): — start a function definition. Its name is total. It takes one input, which we will call expenses inside the function. The colon starts the body.
  • The indented block is the body. It runs each time the function is called, not each time it is defined.
  • return running — the function gives back this value to whoever called it. Without return, the function silently gives back None (Python’s word for “nothing”).

To use it:

total([120, 80, 250, 90, 45])   # 585
total([200, 150])               # 350

Once a function exists, the lines inside it are yours, named. You no longer have to think about how it works each time you total a list. You just write total(...) and trust your past self.

Putting them together

Most useful programs are some combination of loops and functions. A small example with our transaction table from last section:

def total_by_vendor(transactions, vendor):
    running = 0
    for t in transactions:
        if t["vendor"] == vendor:
            running = running + t["amount"]
    return running


transactions = [
    {"vendor": "Khalti",  "amount": 5000},
    {"vendor": "eSewa",   "amount": 1200},
    {"vendor": "Khalti",  "amount":  450},
    {"vendor": "FonePay", "amount":  900},
]

print(total_by_vendor(transactions, "Khalti"))   # 5450
print(total_by_vendor(transactions, "eSewa"))    # 1200

A function with two parameters (transactions and vendor), a loop over the list, and one new piece — an if check inside the loop that says “only add the amount if the vendor matches what was asked for”. The == is “is equal to” (the single = is assignment — they are different).

Read this program twice before moving on. It is the smallest realistic shape of code you will write in the rest of the track.

Code you can reread

A program is read more often than it is written — usually by your future self, six months from now, trying to remember what past-you was thinking. Two small habits cost almost nothing and save enormous amounts of pain.

Name things for what they mean. Compare:

def f(x, y):
    r = 0
    for i in x:
        if i["v"] == y:
            r = r + i["a"]
    return r

with the version above. Same logic, same output. The first version is unreadable in a week; the second tells you what it does at a glance. Variable names cost zero runtime. Use them generously.

Indent consistently. Python forces this on you anyway, but more than that: use four spaces, not tabs, and never mix the two. Every editor on earth — VS Code included — can be set to insert four spaces when you press Tab. Do that once and forget about it.

Use comments sparingly, and for why, not what. A bad comment:

total = total + expense   # add expense to total

The code already says that. A useful comment:

# Skip Saturdays — markets are closed and the totals are zero.
if date.weekday() == 5:
    continue

The comment explains why the strange-looking line is there. That is the only kind of comment worth writing in most cases.

Check your understanding

Quick check

What does this program print? def double(x): return x + x values = [3, 5, 7] result = 0 for v in values: result = result + double(v) print(result)

Quick check

A friend writes this function and is surprised it always returns None: def total(numbers): running = 0 for n in numbers: running = running + n What is the most accurate explanation of the bug?

What comes next

You can now hold data in shapes and move it through functions and loops. The last piece of plain Python is getting data off disk — out of a CSV that someone exported, a JSON that an API returned, a plain text file of receipts you typed yourself. That is the next section, and it is the last stop before the numerical toolkit (NumPy, pandas, matplotlib) in Chapter 3.