JEPA4Japan · tutorials

Functions: Turn Steps into Reusable Tools

1,093 words 5 min read #Python

Package repeated work into functions with parameters, return values, and clear contracts.

Course progress Course outline 24 of 24 lessons available

Turn a recipe into a button

Copying the same steps again and again makes a program long and fragile. A function bundles steps under one name. It is like a button: define what the button does once, then press it whenever you need that job.

  1. Define write the recipe once
  2. Call press its named button
  3. Receive use the returned result
Define a job once, call it many times, and reuse its result.

You have already called print(), input(), int(), and range(). Now you will define your own functions and rebuild Chapter 2’s calculator with smaller, clearer jobs.

Define, call, and pass values

def creates a function. Its indented body waits until you call it:

def greet_learner():
    print("Ready to study Python!")


greet_learner()
greet_learner()

Output:

Ready to study Python!
Ready to study Python!

The definition is the recipe; greet_learner() is a call. A useful function name says what it does, such as calculate_total() or show_plan().

A parameter is a local label in the recipe. An argument is the value a call gives it:

def describe_session(topic, minutes):
    print(f"Study {topic} for {minutes} minutes.")


describe_session("functions", 35)

Here, topic and minutes are parameters. "functions" and 35 are arguments. Position matters: the first argument goes to the first parameter.

  1. Arguments arrive "functions", 35
  2. Parameters label them topic, minutes
  3. The body works only when called
  4. Local names vanish after this call ends
Each call gets its own temporary parameter names.

Names assigned inside a function are normally local. Trying to use one outside its function raises NameError. Pass needed values in through parameters and send useful results out with return.

Return is not print

print() shows something to a person. return hands a value back to the program. That difference matters:

def double_and_return(number):
    return number * 2


result = double_and_return(15)
print(result + 5)

Output:

35

The returned integer can join another calculation. Compare a function that only displays:

def double_and_show(number):
    print(number * 2)


result = double_and_show(15)
print(result)

Output:

30
None

The first line came from inside the function. Because the function reached its end without returning a value, its result was None.

  1. print() shows a value to a person
  2. return sends a value to the caller
  3. No return the call produces None
Seeing a printed number does not mean the function returned that number.

A function’s small contract says what comes in, what happens, and what comes back. Clear names plus a one-line docstring make that promise visible:

def calculate_total_minutes(minutes_per_day, days):
    """Return the total minutes in a daily study plan."""
    return minutes_per_day * days

When Python reaches return, that call ends immediately. Code placed after an unconditional return in the same block cannot run.

Build a calculator from small jobs

Good small programs separate three jobs: input gathers values, processing returns results, and output presents them. Save this complete standard-library project as study_time_functions.py:

def calculate_total_minutes(minutes_per_day, days):
    """Return the total minutes in a daily study plan."""
    return minutes_per_day * days


def minutes_to_hours(total_minutes):
    """Return minutes expressed as hours."""
    return total_minutes / 60


def show_plan(topic, minutes_per_day, days, total_minutes, total_hours):
    """Display one friendly study plan."""
    print()
    print(f"Topic: {topic}")
    print(f"Daily practice: {minutes_per_day} minutes")
    print(f"Days: {days}")
    print(f"Plan: {total_minutes} minutes")
    print(f"Total time: {total_hours:.1f} hours")


def main():
    topic = input("Topic: ")
    minutes_per_day = int(input("Minutes per day: "))
    days = int(input("Number of days: "))

    total_minutes = calculate_total_minutes(minutes_per_day, days)
    total_hours = minutes_to_hours(total_minutes)

    show_plan(topic, minutes_per_day, days, total_minutes, total_hours)


main()

Run it and enter Python, 30, and 7. Verify the final section:

Topic: Python
Daily practice: 30 minutes
Days: 7
Plan: 210 minutes
Total time: 3.5 hours

You can also test the processing jobs without typing input:

print(calculate_total_minutes(45, 4))
print(minutes_to_hours(180))

Both lines should print 180 and 3.0. This is why small calculation functions are easy to check.

Three tiny missions and clear contracts

  1. Days to minutes. Write days_to_minutes(days, hours_per_day) and return the answer. days_to_minutes(3, 2) should return 360; print outside the function.
  2. Target helper. Write target_met(actual, target) that returns a Boolean. Test (29, 30), (30, 30), and (31, 30).
  3. Reusable label. Write session_label(topic, minutes) that returns text such as Python: 40 minutes. Save its result and print it twice.

Sharp corners: calling a function with the wrong number of arguments raises TypeError. Text passed to int() raises ValueError, and zero days is safe for multiplication but not for an average that divides by days. Later chapters will add defaults, type hints, and friendly input validation.

Ready to work with text?

  • I can define a function and call it later.
  • I can identify parameters and arguments.
  • I can pass several arguments in the intended order.
  • I know that print() displays while return sends a value back.
  • I know why a function with no explicit return produces None.
  • I can keep temporary names local to a function.
  • I can describe input, work, and result in a short contract.
  • My refactored calculator produces 210 minutes and 3.5 hours.
  • I completed the three tiny missions.

Next, you will reuse these small functions while inspecting, normalizing, searching, splitting, and joining Unicode text.