Functions and imports
Write a reusable function, understand arguments and return values, and load the libraries used by a model script.
Work here, beside the explanation
Functions let you give a reusable sequence of instructions a name. This is like a reusable procedure made from blocks, now typed with parameters and a return value. Imports let you use procedures written in a library. Build your own small function before calling the much larger procedures that load and train a model.
Each numbered stage below shows a complete program. Try this stage copies it into the editor beside the article, including every line it needs from earlier stages, so it works even after you reload the page. Read the program first, predict what it will print, then press Run. Loading a stage replaces what is in the editor; Undo brings your own version back.
Build with me · 1
1. Define a procedure
def begins a function definition. Its name is count_label. The names inside parentheses are parameters: places for values a caller will supply. Defining the function stores the procedure; it does not yet run its indented instructions. The display after the definition is outside the body. The counter begins anew whenever the procedure is called, so separate calls do not accidentally share its running total.
def count_label(labels, wanted): count = 0 for label in labels: if label == wanted: count += 1 return countprint("Function defined; no counting call yet.")Run and notice that defining the function does not print a count.
What to look for
Only the final explanatory message appears.
Make it yours
Rename the function consistently to a name you find clearer. Keep the parameters in the same order.
Build with me · 2
2. Call it with arguments
In the call, examples and 2 are arguments: concrete values supplied to the parameters labels and wanted. During this call, labels refers to your six-element list and wanted refers to two. return count ends the call and sends its result back, allowing the assignment to twos to store it. The return is after the loop but still inside the function. Returning inside the loop would stop after the first element.
def count_label(labels, wanted): count = 0 for label in labels: if label == wanted: count += 1 return countexamples = [2, 7, 2, 4, 7, 2]twos = count_label(examples, 2)print("Twos:", twos)Trace which values reach each parameter, then run.
What to look for
The program prints Twos: 3.
Make it yours
Choose a different wanted label and adjust the printed label to match.
Build with me · 3
3. Reuse the same definition
Three calls use one definition. Each call creates its own local count and completes before print receives the result. Nesting a function call inside print is like putting the result of one block into another block's input slot. The last call returns zero because zero occurs no times; absence of matches is still a meaningful numerical answer. It is different from returning None, which usually means no value was returned.
def count_label(labels, wanted): count = 0 for label in labels: if label == wanted: count += 1 return countexamples = [2, 7, 2, 4, 7, 2]print("Twos:", count_label(examples, 2))print("Sevens:", count_label(examples, 7))print("Zeros:", count_label(examples, 0))Predict all three counts and then run.
What to look for
The counts are 3, 2, and 0.
Make it yours
Call the function with a completely different list, including an empty list, and explain the results.
Build with me · 4
4. Distinguish displaying from returning
The first function shows eight but does not explicitly return a value, so its caller receives None. The second returns eight without displaying it; the later print reveals the stored result. Printing is an output action. Returning transfers a value to the caller, where it can be used in another calculation. A model-preparation function must return prepared data, not merely show it, because the model needs those values as inputs.
def display_double(number): print(number * 2) def return_double(number): return number * 2 shown = display_double(4)stored = return_double(4)print("Result of display function:", shown)print("Result of return function:", stored)Run and distinguish the line produced inside a function from the two lines produced afterward.
What to look for
You see 8, then a result of None for the display function, and a result of 8 for the return function.
Make it yours
Add print(stored + 1) to confirm the returned number can be used in a later calculation.
Build with me · 5
5. Check a reusable calculation
Parameters do not guarantee sensible values. This function checks its assumptions before dividing: total must be positive, and correct must be a possible count. or catches either invalid end of the range. A helpful exception explains the input contract rather than quietly returning nonsense. For a small known example, you can calculate the answer yourself and check whether the procedure matches your intention.
def accuracy(correct, total): if total <= 0: raise ValueError("Total must be positive.") if correct < 0 or correct > total: raise ValueError("Correct must be between zero and total.") return correct / total print("Accuracy:", accuracy(17, 20))Run the valid example, then try total equal to zero and read the deliberate error. Restore valid counts.
What to look for
The valid calculation returns 0.85; invalid inputs produce the message written in the function.
Make it yours
Choose your own valid counts and compute their ratio independently before running.
Build with me · 6
6. Import a library function
A library is a collection of functions other people have written for you to use. A module is one file of such functions; math is a module that comes with Python. from math import sqrt makes its square-root function available under the name sqrt. After that, calling it is exactly like calling your own count_label: a name, then arguments in brackets. Importing only makes code available; it does not download anything new. The libraries this course needs are already set up in the browser, though they may take a moment to load the first time.
from math import sqrtprint("Square root of 9:", sqrt(9))Run and compare the argument 9 with the returned result.
What to look for
The result is 3.0, a floating-point number.
Make it yours
Try another perfect square. Then try a positive non-square to see a decimal result.
Build with me · 7
7. Give a library a short name
NumPy is the library most Python programs use for working with lots of numbers at once. import numpy as np imports it under the short name np, which nearly every example you will ever see uses. np.array([0, 8, 16]) makes a NumPy array: like a list of numbers, but built for maths. The big difference: dividing an array by 16 divides every number in it, in one step, while dividing an ordinary list by 16 is an error. The dot means "belonging to": np.array is the array tool belonging to NumPy, and scaled.shape is the shape belonging to scaled. (3,) means three values in a single row; the comma is how Python writes a group containing one number.
import numpy as npvalues = np.array([0, 8, 16])scaled = values / 16.0print("Original:", values)print("Scaled:", scaled)print("Shape:", scaled.shape)Run and compare every original value with its scaled partner.
What to look for
The scaled values are 0, 0.5, and 1, in an array of shape (3,).
Make it yours
Add another brightness value between 0 and 16 and predict its normalised result.
Build with me · 8
8. Load real digit data with an import
scikit-learn, imported under the name sklearn, is a machine learning library, and it comes with a small collection of handwritten digit images. load_digits() returns that collection as one object, here named digits, which holds several parts. The dot picks a part: digits.data is a table with one row per image and 64 brightness values per row, and digits.target holds the correct digit for each row, in the same order. The name X is used for the table of inputs and y for the answers, a habit shared by most machine learning code. .astype("float64") stores the numbers as decimals so that dividing works cleanly, and dividing by 16 turns the original brightness range of 0 to 16 into 0 to 1. Loading data does not train anything.
from sklearn.datasets import load_digitsimport numpy as np digits = load_digits()X = digits.data.astype("float64") / 16.0y = digits.targetprint("Examples:", len(y))print("Input shape:", X.shape)print("First true label:", y[0])Run and identify which object is the returned bundle and which names refer to its numerical data.
What to look for
There are 1,797 examples, the input shape is (1797, 64), and the first true label is 0.
Make it yours
Print a different valid label position and keep its relationship to the same input row explicit.
Build with me · 9
9. Use your own function on library data
Your counting function can iterate over this one-dimensional NumPy array just as it iterated over a list. A reusable procedure is useful when its input contract matches another source of data. It does not need to know how the dataset was loaded. The caller supplies the labels and the wanted value; the procedure returns the count. This separation makes errors easier to locate: loading, counting, and displaying each have a clear job.
from sklearn.datasets import load_digitsimport numpy as np digits = load_digits()X = digits.data.astype("float64") / 16.0y = digits.target def count_label(labels, wanted): count = 0 for label in labels: if label == wanted: count += 1 return count wanted = 7print("Wanted label:", wanted)print("Matching examples:", count_label(y, wanted))print("All examples:", len(y))Run for a chosen digit, then compare a second digit using another call.
What to look for
The counts are measured from the actual packaged dataset and may differ between digits. All examples still totals 1,797.
Make it yours
Print counts for every digit using for wanted in range(10): and an indented call to your function.
Reuse a procedure deliberately
A function definition names a procedure; calling it runs that procedure with particular arguments. A returned value can be stored and used by later code, while print only displays a result. Names created inside a function belong to that call unless explicitly passed back. Imports make available code visible under a name; they do not install missing packages. Put imports and definitions before the calls that depend on them, and test a function on a tiny known example before connecting it to the digit dataset.
The complete reference is folded away below. Compare it with your work after trying the steps; changing a personal choice such as a name, a colour, or a display threshold can produce a different valid program.
Full reference solution
This is the final complete program built in the walkthrough. All its setup is included. Personal choices may differ in your own version; model scores are measured when you run, not promises about a future dataset.
from sklearn.datasets import load_digitsimport numpy as np digits = load_digits()X = digits.data.astype("float64") / 16.0y = digits.target def count_label(labels, wanted): count = 0 for label in labels: if label == wanted: count += 1 return count wanted = 7print("Wanted label:", wanted)print("Matching examples:", count_label(y, wanted))print("All examples:", len(y))Compare this with your version. Different names and personal choices are fine when the program follows the same logic.
Keep your progress
Sign in and every reading, quiz, and exercise you finish is saved.