Python for Humans · Draft v0.1 · Oct 27, 2026 · Draft position: chapter 7 · First draft; introduce calls, parameters, return and local names through reusable word counting.
Giving Code a Name
- You should already know
- Variables, decisions, loops, lists, and dictionaries; the word-counting loop from chapter 6.
- You'll build
- A count_words() function you can use with a sentence or a whole book.
- You'll be able to
- Define and call a function, pass arguments to parameters, return a result, and understand names local to a call.
- You need
- This page. Python runs in the panel beside it; installing Python on your own computer comes in chapter 9.
Our counter works on a sentence or a whole book. But suppose we want to compare two texts. We could copy the counting loop, change the input, and run it again.
What happens when we improve the punctuation rule? We'd have to remember to change every copy.
Python lets us give a group of instructions a name. Then we can ask it to run those instructions whenever we need them. That's a function.
You've already called functions such as print(), input(), and len(). Now we'll write our own.
Give Instructions a Name
Start with a small runnable example:
def welcome(): print('Welcome to the castle!') print('Please leave your dragon outside.') welcome() welcome()
def begins a function definition. We chose the name welcome. The parentheses and colon are part of the definition, and the indented lines are the function's body.
The definition tells Python what to do when we call welcome(). It doesn't run the body immediately.
The first welcome() after the definition calls the function. Python runs the two indented instructions, then returns to the next line after that call. The second call runs them again.
Try it: Remove both calls and run the program. No greeting appears. Put one call back, then change a message inside the function. Every call now uses the updated instructions.
Give It Something to Work With
A function becomes more useful when it can work with different values.
def welcome(name): print(f'Welcome to the castle, {name}!') welcome('Mira') welcome('Dragon')
The name name inside the definition is a parameter. Each call supplies a value for it. The supplied value is called an argument.
On the first call, name refers to 'Mira'. On the second, it refers to 'Dragon'. The body stays the same; the value it works with changes.
Your turn: Add a third call with a name you choose. Then change the function to ask the guest to bring pizza, using their name in the request.
The parameter name doesn't have to match a variable outside the function. We could write guest = 'Mira', then call welcome(guest). Python passes the value to the parameter.
Get a Result Back
Displaying a greeting is useful, but what if we want a value we can use in another calculation?
def double(number): return number * 2 result = double(7) print(result) print(result + 1)
return sends a value back to the place where the function was called. Here double(7) produces 14, which we assign to result. We can display it or use it in another expression.
Returning and printing do different jobs. return gives the caller a value; print() displays something on the screen.
Try it: Replace return number * 2 with print(number * 2) and run again. You'll see 14 printed inside the function, but the call now produces None, Python's value for no result here. result + 1 then fails because None isn't a number.
Put return back and check that the program works again. A function that finishes without executing a return statement returns None automatically.
return also ends the function call immediately. Instructions after it in the same path don't run.
Wrap the Counter
Let's apply that shape to our word counter. We'll pass in some text, build the dictionary, and return it.
The counting body is the same code we developed in chapter 6. Its extra indentation puts it inside the function.
def count_words(text): words = text.split() counts = {} for word in words: word = word.lower() word = word.strip('.,!?;:') if word != '': if word in counts: counts[word] = counts[word] + 1 else: counts[word] = 1 return counts first_counts = count_words('Dragon, pizza! DRAGON.') second_counts = count_words('Pizza for the dragon. Pizza!') print(first_counts) print(second_counts)
We wrote the loop once, then called it twice with different arguments. Each call starts with a fresh empty dictionary. The second call doesn't add to the first call's counts.
Notice where return counts sits. It belongs to the function, but it's outside the loop. We want to finish counting all the words before giving the dictionary back.
Your turn: Add a third call with your own short text. Give the result a name and print the count for a word you know is present. Predict it before running.
Then change the punctuation string inside the function to include another punctuation character you want to remove. That single change now applies to every call. Keep the same modest expectation as before: this is our chosen cleanup rule, not a complete definition of an English word.
Use the Result
Once a function returns a value, we can use the operations we already know on it.
In the program above, add these lines after the existing calls:
print(first_counts['dragon']) print(len(second_counts))
Predict both outputs before running the program. first_counts and second_counts refer to ordinary dictionaries. They don't need special treatment because a function created them.
Now use the Python panel to try a very small function. Type the def line and press Enter. The prompt changes to ..., and the panel indents the next line for you. Type the return line with four spaces before it, press Enter, then submit an empty line to finish the definition. Remove any automatically inserted spaces on that final blank line if necessary.
>>> def double(number): ... return number * 2 ... >>> double(7) 14 >>> double(10) 20
Type a call with a number of your own. You can define functions in the panel, but for a longer definition like count_words, the editable program box makes it easier to revise several lines together.
Names Inside a Function
Where do the function's words and counts go after it runs?
Parameters and names assigned inside a function are local to that call. They let the function do its work without replacing similarly named variables outside it.
def double(number): result = number * 2 return result result = 100 answer = double(7) print(answer) print(result)
The function's local result is 14. The result outside the function is still 100.
We can keep the returned value by assigning it to a name outside, as we did with answer. We don't reach into the function to fetch its local names.
Try it: Rename the outside result to starting_score, changing its final print() too. Does the function need to change? Then call double() again with another number and store that answer under a different name.
Read a File, Then Count It
Go back to the box containing count_words(). Keep the definition, and replace the example calls at the bottom with:
text = open('shakespeare.txt').read() counts = count_words(text) print(counts['love'])
The function accepts text, not a filename. Loading the file is a separate job. That lets us check the counter with a tiny sentence, then use exactly the same function with a book.
Your turn: Add another lookup for a word you choose. Use a membership check if you aren't sure it exists. Then call the function with a small string again. Do you need to change the definition to switch between a sentence and Shakespeare?
Your Turn
Predict
Write down the two output lines before running this. When is the function body actually executed?
def add_one(number): return number + 1 print('Starting') answer = add_one(4) print(answer)
Find the Bug
This function should count all the supplies, but stops after the first one. Fix the indentation of one line.
def count_supplies(supplies): total = 0 for supply in supplies: total = total + 1 return total print(count_supplies(['torch', 'map', 'pizza']))
Write a Function of Your Own
Write a function called count_long_words that accepts a list of words and returns how many have more than six characters. Reuse the counting pattern above, adding a decision inside the loop. Only return the total after the loop finishes.
words = ['dragon', 'castle', 'treasure']
Keep that list as a small check. Call your function with it and display the result: you should get 1. Then try an empty list and a list with two long words. What should each return?
Optional: Find the Most Common Word
You can continue to the next chapter without this extension. If you'd like practice, write most_common(counts), accepting a word-count dictionary and returning the key with the largest count.
Start best_word at '' and best_count at 0. Loop over the keys; whenever a count is larger than the best so far, update both names. Return best_word after the loop. With an empty dictionary this version returns ''; with equal largest counts it keeps the first key it encountered.
Add it to your counting program and try it with a tiny dictionary before using Shakespeare. You don't need sorting or new syntax to answer this question.
What I've Learned
Write one sentence explaining the difference between printing a value and returning it. Include how the caller can keep a returned value.
What's Next?
We now have lists to hold words, dictionaries to connect words with values, loops to process them, and functions to organize the work.
In The Word-Prediction Generator, we'll combine those pieces to make something stranger: a program that generates new text from Shakespeare. Instead of asking only how often a word occurs, we'll ask which words follow it, then choose where to go next.