How functions receive information from the outside world, and how they send results back — including the most important distinction in beginner Python programming: printing versus returning
Chapter 11 introduced functions as named, reusable blocks of code. You learned how to define a function, how to call it, and how execution jumps into a function and returns when it finishes. But those early functions had a significant limitation: they always did exactly the same thing every time. They could not adapt to different situations, work with different values, or hand a result back to the rest of the program.
This chapter removes that limitation. You will learn how to give information to a function using parameters and arguments. You will learn how functions send results back using return values. You will learn one of the most important distinctions in beginner Python programming: the difference between printing a result and returning a result. And you will learn how to design function interfaces that are clear, reusable, and easy to test.
These ideas are foundational. Everything that follows in this textbook — data structures, files, classes, and projects — depends on writing functions that receive information and return results correctly. Confusing print() with return is one of the most common bugs beginning programmers write, and it is also one of the easiest to fix once you understand the difference clearly.
By the end of this chapter, you should be able to:
parameter and argument, and explain how arguments are matched to parameters by position.return statement to send a value back to the calling code.None is, when a function returns it, and why that can cause errors.def line; single and multiple parameters; key properties of parametersTypeError for missing or extra argumentsreturn statement; sending values back to calling code; how return ends a function immediatelyprint() or returnNone and Missing Return ValuesWhat None means; functions without return; the classic missing-return bug; checking with is NoneImagine you want a function that calculates the area of a rectangle. A rectangle's area is its width multiplied by its height.
Here is a version of that function that does not receive any information:
This function works, but it always calculates the area of a rectangle that is exactly 5 units wide and 3 units tall. It cannot calculate the area of any other rectangle. To calculate a different area, you would have to rewrite the function or write a new one.
That defeats the purpose of writing a function.
The solution is to design the function so that the width and height are supplied by whoever calls it. The function should work for any width and any height, not just specific values baked into the function body.
This is what parameters are for.
Now the function receives the width and height from outside. Every time you call it, you can supply different values. The function does the same calculation every time, but it works on whatever values it receives.
Functions are more useful when they receive the information they need rather than assuming fixed values. A function with parameters can solve a whole family of problems, not just one specific case.
A parameter is a variable that appears inside a function's definition. It acts as a placeholder for a value that will be supplied when the function is called.
Parameters are listed inside the parentheses of the def line, separated by commas.
In this function, name is a parameter. It is a variable that does not exist yet when the function is defined. It will receive a value only when the function is called.
A function can have more than one parameter:
Here animal and pet_name are two parameters. Both receive values when the function is called.
def line.Parameters are not yet real values when you write the function definition. They are named slots. The real values arrive from outside, at the moment of the function call.
An argument is the actual value that is passed into a function when you call it. Arguments fill the parameter slots.
Here, "Maria" is the argument. When the function call executes, name receives the value "Maria". From that point on, inside the function, name is "Maria".
Here, "cat" is the argument for animal and "Luna" is the argument for pet_name.
Arguments are matched to parameters by position. The first argument goes to the first parameter, the second argument to the second parameter, and so on.
When this runs:
width receives 10height receives 4area becomes 4040If you reverse the arguments, the parameters receive different values:
For calculate_area, the result is the same because multiplication is commutative. But for other functions — such as one that calculates a price after discount — the order matters significantly. Be careful to supply arguments in the correct order.
| Term | Where It Appears | What It Is |
|---|---|---|
| Parameter | Function definition (def line) | A placeholder variable |
| Argument | Function call | The actual value supplied |
Functions can accept multiple parameters. Each parameter is a separate variable inside the function, and each receives a corresponding argument.
Tracing this call:
price receives 12.99quantity receives 3tax_rate receives 0.08subtotal becomes 38.97tax becomes 3.1176total becomes 42.087642.0876You must supply exactly the right number of arguments. If a function has three parameters and you call it with two arguments, Python raises a TypeError:
The error message is informative. It tells you which argument is missing. Read error messages carefully — they are your first debugging tool.
Similarly, supplying too many arguments is also an error:
The function works for any destination, distance, and number of days. Try calling it with different arguments.
So far, every function in this chapter has displayed its result using print(). That works for showing information to a user, but it has a serious limitation: the result vanishes after it is printed. No other part of the program can use it.
Consider this function:
If you call calculate_area(10, 4), it prints 40. But what if you want to use that area in a larger calculation — say, to figure out the cost of flooring at a certain price per square unit? You cannot, because the value 40 was only printed, not stored or passed anywhere.
The solution is for the function to return its result.
The return statement sends a value back to wherever the function was called. The calling code can then store it, use it in an expression, print it, or pass it to another function.
Now when you call this function, it produces a value that the rest of the program can use:
You can also use the returned value directly in an expression:
return Does1. It sends a value back to the calling code.
2. It immediately ends the function's execution.
Any code written after a return statement in the same function will not run:
The return statement is one of the most important tools in function design. Learn to use it consistently.
One of the most common mistakes beginners make is confusing print() and return. This section explains the difference clearly and directly.
print() displays a value on the screen. That is all it does. The value is shown to the user, and then it is gone. No other part of the program can work with it further. return sends a value back to the calling code. The calling code can store it, use it, pass it forward, or print it. The value lives on.
Here are two versions of the same function. Read them carefully:
Now watch what happens when you try to use the result:
With Version A:
double(5) runs and prints 10 to the screen immediately.None (nothing).result receives None.print(result) line prints None.With Version B:
double(5) runs silently.10.result receives 10.print(result) line prints 10.The difference matters enormously when you want to use a function's result in further calculations, store it in a list, write it to a file, or pass it to another function. A function that only prints cannot do any of those things. A function that returns can.
If a function computes a value that the rest of the program needs, use return. Use print() only when the function's specific job is to display information. A practical test: ask yourself, "Does the rest of my program need this value?" If yes, use return. If the function's only job is to show something to the user, print() is appropriate — but even then, it is often cleaner to return the value and let the calling code decide whether to print it.
10. total is 10. print(total) prints 10.10 immediately. It returns None. result is None. print(result) prints None.When a function returns a value, that value can be used anywhere an expression is valid. You can use it in arithmetic, comparisons, assignments, other function calls, or print statements.
You can also pass the result of one function directly as an argument to another:
double(3) is called. Returns 6.square(6) is called with 6. Returns 36.print(36) prints 36.This kind of composition — using the result of one function as the argument to another — is a powerful and natural pattern in Python. Keep it simple and readable. If a chain of function calls becomes hard to read, break it into separate assignment steps.
Clarity is more valuable than compactness, especially while you are learning.
None and Missing Return ValuesIn Python, every function call produces a value. If a function does not have a return statement, or if execution reaches the end of the function without hitting return, the function automatically returns a special value called None.
None represents the absence of a value. It is not zero, not an empty string, not False. It is its own type, called NoneType.
greet does not have a return statement, so it returns None. When you assign the result of a call to greet to a variable, that variable holds None.
This is often a source of bugs. A common mistake looks like this:
The programmer printed the tip but forgot to return it. When the code tries to add tip_amount to the bill, it gets a TypeError because tip_amount is None, not a number.
Replace print(tip) with return tip.
Checking for None: you can check whether a variable holds None using is None:
is None, Not == NoneThe is operator checks identity, which is the correct way to test for None in Python.
Functions without return produce None.
Functions that hit a bare return with no value also produce None.
Storing or using None where a number or string is expected causes errors.
Always check whether your function is supposed to return something, and if so, make sure it does.
Sometimes a function has a parameter that usually takes the same value, but occasionally needs a different one. Python lets you assign a default value to a parameter. If the caller does not supply that argument, the default is used automatically.
This function has two parameters: name and greeting. The parameter greeting has a default value of "Hello".
You can call it with one argument:
Or with two arguments to override the default:
Default parameters make functions more flexible without requiring callers to always supply every detail.
Default parameters must come after non-default parameters in the function definition.
This is valid: def f(a, b=10):
This is a SyntaxError: def f(a=10, b): — you cannot have a required parameter after a default parameter.
Default parameters are useful for optional settings, standard rates, default messages, and any case where one value makes sense for most callers but the function should still accept alternatives.
You do not need to use default parameters in every function. Apply them when they genuinely make a function easier to use without hiding important decisions.
A function's interface is the combination of its name, its parameters, and its return value. The interface is what other parts of the program see and use. The body is the hidden implementation.
A well-designed function interface has these qualities:
calculate_area, is_valid_password, get_average, format_name. Avoid vague names like do_stuff, helper, or process.get_and_print_and_save_the_total is trying to do too much. Separate concerns into separate functions.score and maximum.calculate_percentage is clear and specific.Step 5 — Test it:
This function is short, clear, and testable. It does one thing. It returns its result. It does not print anything. The caller decides what to do with the percentage.
Mixing computing and printing in the same function makes the function harder to reuse:
Hard-coding values that should be parameters locks the function into one specific case:
Taking too many parameters makes a function hard to call correctly. If you find yourself writing a function with five or more parameters, consider whether it should be broken into smaller functions.
Good function design is a skill that develops with practice. Start simple. Keep functions small. Return values rather than printing them. Test each function separately before combining them.
parameter is a placeholder variable listed in a function's def line. Parameters are local to the function and receive their values only when the function is called.argument is the actual value supplied at the call site. Arguments are matched to parameters by position — the first argument fills the first parameter, and so on.TypeError.return statement sends a value back to the calling code and immediately ends the function. Code written after return in the same function never runs.return whenever the rest of the program needs the computed value.return statement automatically returns None. Using None where a number or string is expected causes a TypeError. Test for it with is None.def line that acts as a placeholder for information the function will receive when called.return statement.return statement return None automatically.None. When None is used where a number or string is expected, Python raises a TypeError.return statement in a function body and can never execute.Read each function carefully. Do not run the code yet. Answer the questions based on your reading.
6 and 7 as arguments.format_greeting("Patel") produce?format_greeting("Patel", "Dr.") produce?compute return a value?compute(8, 5) itself?total hold after the assignment?print(total) print?is_even return?is_even(4) return?is_even(7) return?Trace each program step by step. Write out every variable value as it changes. Predict the complete output before checking.
| Step | Variable | Value |
|---|---|---|
Call add_tax(20.00, 0.10) | price | ? |
rate | ? | |
| Inside function | tax | ? |
total | ? | |
| Return | — | ? |
| After call | cost | ? |
What is printed?
Trace both calls. What are a and b? What is the output?
Trace the call to sum_of_squares(3, 4). Note when square is called and what it returns each time. What is printed?
Read each program and write the exact output it will produce. Watch carefully for the difference between printing and returning.
Program 1These questions target the most common confusion in this chapter.
print the grade or return it? Explain your reasoning.print or return? Explain.calculate_discount. Another function, calculate_total, needs to use the discount in a further calculation. What does this tell you about how calculate_discount should be written?What is the output? What is the bug? How would you fix it?
return. With no value after return, what does the function return?Each program below contains one or more errors. Identify the error, explain what is wrong, and write a corrected version.
(This code technically runs. What is wrong with it logically or stylistically?)
Write a complete Python function for each task. Test each function with at least two different sets of arguments.
calculate_perimeter that takes the length and width of a rectangle and returns the perimeter (2 × length + 2 × width).is_passing that takes a score (0–100) and returns True if the score is 60 or above, and False otherwise.full_name that takes a first name and a last name and returns them joined with a space between them.clamp_temperature that takes a temperature and returns it unchanged if it is between -50 and 150 (inclusive), returns -50 if it is below -50, and returns 150 if it is above 150.describe_bmi that takes a weight in kilograms and a height in meters, calculates the BMI (weight divided by height squared), and returns the BMI as a float rounded to one decimal place. (Use Python's round() function.)repeat_string that takes a string and an integer and returns the string repeated that many times. For example, repeat_string("ha", 3) should return "hahaha".shipping_cost that takes the weight of a package in kilograms and returns the shipping cost. The cost is 5.00 for the first kilogram and 2.50 for each additional kilogram. A default parameter should set the base rate to 5.00 and the per-kg rate to 2.50, but the caller can override either.Build a small calculator program using a collection of well-designed functions. Your calculator should support addition, subtraction, multiplication, and division.
Each arithmetic operation should be its own function. Each function should take two numbers as parameters and return the result.
Division should handle the case where the second number is zero (return None or a message, and do not crash).
A main function should ask the user to enter two numbers and choose an operation, call the appropriate function, and display the result.
Add a power function that raises the first number to the power of the second. Add a square_root function using Python's ** operator (hint: the square root of n is n ** 0.5). Wrap the calculator in a loop so the user can keep calculating until they choose to quit. Add input validation so the program handles non-numeric input without crashing.
These questions draw on skills from earlier chapters alongside the new material in Chapter 12.
count_even that takes two integers — a start and an end — and returns the count of even numbers in that range (inclusive of both endpoints). Use a for loop inside the function.grade_letter that takes a numeric score and returns the letter grade: A (90–100), B (80–89), C (70–79), D (60–69), F (below 60). Use elif chains inside the function.average_of_three to calculate the average. Write both the function and the calling code.print() to show its result is harder to reuse than a function that uses return.parameter and argument and explain how they are matched by position.return statement to send a value back to the calling code.None is and why functions without return produce it.TypeError about argument counts comes from too few or too many arguments.None, I check whether the function that produced it is missing a return.is None rather than == None when testing for None.Chapter 12 gave you tools for passing information into functions and getting results back. But there is an important question we have not fully answered yet: what happens to variables that are defined inside a function? Can the rest of the program see them? Can the function see variables defined outside it?
These questions are about scope — where a variable exists and how long it lives. Chapter 13 explores local variables, global variables, variable lifetime, and program state. You will learn why variables defined inside a function are separate from variables with the same name outside it, why functions should usually communicate through parameters and return values rather than sharing variables, and how to avoid the confusing bugs that arise when scope is misunderstood.
Understanding scope is essential before functions can be used to build larger, more organized programs.