A science club receives temperatures in Celsius, but its display needs Fahrenheit. Your challenge is to build one converter tool, call it with several temperatures, and trust it to give a usable result every time.
By Lesson 3, you will package calculations and even a turtle polygon into tools with their own inputs and local names.
You will learn
- Define and call a reusable function with
def. - Give a function inputs through parameters and send a value back with
return. - Use built-in number tools for common calculations.
- Tell which names belong inside a function and which result the caller receives.
Lesson 1: Define & Call
A science club receives Celsius readings and needs one reusable Fahrenheit tool. First, see how a function is defined and called.
Functions that only print
Define greet with no parameters. Its indented body runs only when you call it.
def greet():
print("Hello!")
greet()
Output
Hello!Notice
Defining the function displays nothing. The call displays Hello!. This function prints but returns no useful value.
Now give greet one parameter. The caller supplies a name for that local value.
def greet(name):
print("Hello, " + name + "!")
greet("Maya")
Output
Hello, Maya!Notice
The call displays Hello, Maya!. name receives the argument for this call; the function still only prints.
Build the temperature-converter tool
A function is a named tool. This time it sends a result back with return. The input is a Celsius temperature, and the returned result is Fahrenheit.
def celsius_to_f(c):
fahrenheit = c * 9 / 5 + 32
return fahrenheit
print(celsius_to_f(-10))
print(celsius_to_f(0))
print(celsius_to_f(25))
Output
14.0
32.0
77.0Visible payoff: one tool handles several inputs. The three calls return 14.0, 32.0, and 77.0. The / calculation makes each result a float.
Read the definition from top to bottom:
deftells Python that a function definition starts.celsius_to_fis the function's meaningful name.cis a parameter, a local name that receives one call's input.- The indented lines are the function body.
return fahrenheitsends the computed value back to the caller.
The definition stores the tool. A call such as celsius_to_f(25) uses it.
Small tools with one clear job
A function can return an integer or a boolean just as it can return a float. These two tools name their jobs and their inputs.
def square(n):
result = n * n
return result
def is_even(n):
return n % 2 == 0
print(square(5))
print(is_even(14))
print(is_even(9))
Output
25
True
FalseNotice
square(5) returns the integer 25. is_even(14) returns True, while is_even(9) returns False. The caller decides whether to print, save, compare, or calculate with a returned value.
Notice
Notice: printing is not returning
This function displays a number, but it does not return that number. Predict what happens when the caller tries to add 1 to the missing result.
Read the error
def f(n):
print(n * n)
total = f(3) + 1
print(total)
Python first prints 9, then reports:
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Read the last line first. The + operation received a NoneType value and an integer. A function with no return gives back None, which means no useful value was returned. The caller cannot add 1 to that missing value.
Fix the boundary: let the function return its result, then let the caller choose to print or calculate with it.
def f(n):
return n * n
total = f(3) + 1
print(total)
Output
10Notice
The fixed call produces 10. print sends text to the screen; return sends a value to the caller. Exercise 2 is the one practice item pinned to this trap. In your other functions, focus on the value promised by the specification.
Try a real temperature
This interactive version reads one Celsius value, calls the converter, and displays its result.
Try it yourself
celsius = float(input("Celsius: "))
print(celsius_to_f(celsius))
Lesson 2: Functions that Compute
A number-puzzle table needs four reusable tools: test a prime, find a shared divisor, produce a Fibonacci number, and total the integers through a chosen endpoint. Each tool hides a loop behind a name and returns one answer.
Leave early with return
first_multiple(start, k) searches from start upward. The first matching number is returned immediately; the loop does not keep searching.
def first_multiple(start, k):
number = start
while True:
if number % k == 0:
return number
number = number + 1
print(first_multiple(10, 4))
Output
12Notice
The result is 12. Once return runs, the function is finished; later loop trips do not happen.
Test whether a number is prime
For n >= 2, try possible divisors from 2 through n - 1. The loop counter divisor names the number currently being tested. A divisor that leaves remainder 0 proves the answer is False; otherwise the function reaches return True.
def is_prime(n):
for divisor in range(2, n):
if n % divisor == 0:
return False
return True
print(is_prime(29))
print(is_prime(35))
Output
True
FalseNotice
is_prime(29) returns True; is_prime(35) returns False as soon as divisor 5 is found. For n == 2, range(2, 2) supplies no values, so the final True is correct.
Try a real prime test
Read one integer and let is_prime test it.
Try it yourself
n = int(input("Number: "))
print(is_prime(n))
Greatest common divisor with while
Euclid's algorithm repeatedly replaces a pair with the second number and the remainder. When the second number becomes 0, the first number is the greatest common divisor. The changing b controls the loop.
def gcd(a, b):
while b != 0:
remainder = a % b
a = b
b = remainder
return a
print(gcd(48, 18))
print(gcd(77, 28))
Output
6
7Trace gcd(48, 18): the pairs become 48 and 18, then 18 and 12, then 12 and 6, then 6 and 0. The returned answer is 6. This is the least intuitive Lesson 2 tool, so it is the first item to defer when time is short.
Carry two Fibonacci values
The Fibonacci sequence starts 0, 1, 1, 2, 3, 5, 8, and so on. Two variables carry the current pair. A temporary variable named nxt protects the newly calculated value while a and b move forward.
def fib(n):
a = 0
b = 1
for step in range(n):
nxt = a + b
a = b
b = nxt
return a
print(fib(0))
print(fib(1))
print(fib(7))
Output
0
1
13Notice
The calls return 0, 1, and 13. The pair is updated in three clear steps: nxt = a + b, then a = b, then b = nxt. Each name holds one value at a time.
A hand-written running total
sum_to_n(n) adds every integer from 1 through n. The name total remembers the running result across loop trips.
def sum_to_n(n):
total = 0
for number in range(1, n + 1):
total = total + number
return total
print(sum_to_n(6))
print(sum_to_n(10))
Output
21
55The calls return 21 and 55. Writing the loop exposes the running-total pattern.
One function can call another
sum_of_squares uses the square helper defined in Lesson 1. This is composition: small tools work together.
def sum_of_squares(n):
total = 0
for number in range(1, n + 1):
total = total + square(number)
return total
print(sum_of_squares(3))
Output
14Notice
The result is 14 because square supplies 1, 4, and 9. The caller sees one result from sum_of_squares.
Python also provides small, already-built functions for common number jobs.
Built-in number tools
A built-in function is ready to call without defining it first. In this unit, use these number tools:
max(a, b)returns the larger of two numbers.min(a, b, c)returns the smallest of three numbers.sum(range(1, n + 1))totals the integers supplied by a range.abs(number)returns distance from zero.round(number)returns a nearby whole number.range(...)is the callable that supplies integers to aforloop.
The two-argument form round(number, 1) keeps one digit after the decimal point. len counts characters in a string today and items in a list in Unit 10.
print(max(7, 12))
print(min(9, 4, 15))
print(sum(range(1, 6)))
print(abs(-17))
print(round(3.6))
print(round(2.5))
Output
12
4
15
17
4
2Notice
sum(range(1, 6)) returns 15, the same result a hand-written running-total loop would make for 1 through 5. max and min replace repeated comparisons when you only need an extreme number. abs(-17) returns 17.
Rounding has a tie rule worth noticing: round(2.5) == 2. Python sends an exact half toward the nearby even integer. Do not assume every .5 rounds upward.
Count characters in a string
Call the built-in len on a string to count its characters.
print(len("banner"))
Output
6Notice
"banner" has 6 characters, so len("banner") returns 6.
A default parameter
A parameter can have a default value. If the caller omits that argument, Python uses the value in the definition.
def rule(n, symbol="-"):
return symbol * n
print(rule(4))
print(rule(3, "="))
Output
----
===Notice
rule(4) returns ----; rule(3, "=") returns ===. The second call replaces the default symbol.
Lesson 3: Scope
Imagine several teams calling the same scoring tool. Each call needs its own input names so one team's calculation cannot overwrite another's. Scope describes where a name can be used.
Parameters and body names are local
A parameter is a local name. A name first assigned in the function body is local too. Each call gets fresh local values.
score = 10
def add_bonus(score):
bonus = 3
score = score + bonus
return score
new_score = add_bonus(score)
print(score)
print(new_score)
Output
10
13The caller's score stays 10, and new_score becomes 13. Inside add_bonus, the parameter named score is local. Changing that local name does not leak out and replace the caller's name.
A function should take what it needs through parameters and return its result, rather than relying on outside names. This makes the tool honest about what it needs and what it provides.
Scope application: a polygon tool
Unit 06 drew polygons with repeated turtle commands. Now package that drawing rule as draw_polygon(n, side). The parameters n and side, the calculated angle, and the loop counter corner are local names inside this function.
The real program (assets/l3_draw_polygon.py)
# Bring in Python's turtle drawing tools.
import turtle
# Draw one closed regular polygon.
def draw_polygon(n, side):
angle = 360 / n
turtle.pendown()
for corner in range(n):
turtle.forward(side)
turtle.left(angle)
turtle.pencolor("darkviolet")
draw_polygon(6, 56)
turtle.done()
Program
# Bring in Python's turtle drawing tools.
import turtle
# Draw one closed regular polygon.
def draw_polygon(n, side):
angle = 360 / n
turtle.pendown()
for corner in range(n):
turtle.forward(side)
turtle.left(angle)
turtle.pencolor("darkviolet")
draw_polygon(6, 56)
turtle.done()
Program
# In the real program (assets/l3_draw_polygon.py), draw_polygon is defined above.
# Adding these two lines at the very end would show that `angle` is local to the function:
draw_polygon(6, 56)
print(angle)
Notice
The call can use angle while draw_polygon is running, but the next line cannot use that local name. Python reports NameError: name 'angle' is not defined. Read the error from the end: angle is not defined where print(angle) tried to use it.
Run the matching real program from this unit directory:
assets/l3_draw_polygon.py
The call supplies 6 and 56. Inside that one call, n is 6, side is 56, and angle is 360 / 6. The loop makes six pen-down moves and closes the hexagon. turtle.done() remains once at the end of the file, outside the function.
Return the result across the boundary
Local work stays protected inside a function, but a returned value crosses back to the caller on purpose.
def safe_temperature(c):
fahrenheit = c * 9 / 5 + 32
bounded = max(fahrenheit, 32)
return round(bounded)
display_temperature = safe_temperature(-8)
print(display_temperature)
Output
32Put it together: the caller provides an argument, the parameter receives it as a local name, the body computes with other local names, and return sends one result back. Meaningful names and short purpose comments make the boundary readable.
Try a real Celsius reading
The real program reads a value and passes it through safe_temperature.
Try it yourself
celsius = float(input("Celsius: "))
print(safe_temperature(celsius))
Recap
defgives a reusable set of instructions a name.- Parameters receive arguments when you call the function.
returnsends a value back;print()only displays one.- Built-in tools such as
max()andround()handle common number jobs. - Names made inside a function are local to that call.
You can now build a Celsius-to-Fahrenheit converter you can call with many readings.