Chapter 16: Functions
Every year the students of a school in Jaipur print certificates for the annual sports day. This year the computer club offered to do it with a Python program. Aarti wrote the part that printed the school name, the event name and the winner’s name. It took about ten lines. Then she copied those ten lines for the second event. Then for the third. By evening the file had the same ten lines repeated forty times.
The next morning the principal noticed a spelling mistake in the school name. Aarti had to correct it in forty places, and she still missed two of them.
Riyaz suggested something simpler. Write those ten lines once, give them a name, and then use that name every time a certificate is needed. If the school name ever changes, you change it in one place only. The rest of the program does not have to be touched at all. That idea, of naming a block of instructions and using the name instead, is what this chapter is about. See Fig. 16.0-1.
Diagram
Fig. 16.0-1 – On the left, a tall box labelled “Same 10 lines of code, copied 3 times” showing three identical stacked blocks. On the right, a single box labelled “print_certificate” with three arrows pointing into it from three small boxes labelled “Event 1”, “Event 2”, “Event 3”. A short caption strip between the two halves reads “written once, used many times”.
The sections ahead will answer all five of these questions.
16.1 Why We Need Functions
In the school canteen, the recipe for lemon sharbat is written once on a card and kept in a box. When an order comes, the cook picks up the card and follows it. Nobody writes the whole recipe again on every order slip. The recipe is stored in one place, given a name, and used whenever it is needed.
A program can be organised in the same way. Some jobs come up again and again — printing a certificate, checking a battery level, converting marks into a percentage. Instead of typing those instructions every time, you can write them once, give them a name, and then use the name.
The problem with repeating code
Look at what happens when you do not do this. A school robotics lab has three robots, and the teacher wants a short battery report for each one.
The program works, but look at what it costs you. The same six lines appear three times. If the lab adds a fourth robot, you copy them again. If the teacher later decides that the charging limit should be 40 instead of 30, you have to find and change that number in three separate places. Miss one, and the report quietly gives a wrong status for that robot.
That last point is the real danger. A program with repeated code does not break loudly when you edit it carelessly. It keeps running and gives an answer that looks fine but is wrong.
Writing it once instead
A better plan is to write the six lines once, give that block a name such as battery_report, and then use the name three times with a different robot each time. The instructions live in exactly one place. Change them there, and every use of the name gets the change automatically.
A block of instructions written once, given a name, and used whenever needed is called a function.
You have already been using functions without calling them by that name. print() is a function. So is input(). Somebody wrote the instructions for putting text on the screen once, gave them the name print, and every Python programmer in the world now uses that one name instead of writing those instructions again.
What functions give you
Three things follow from writing a block once and naming it well.
The program becomes shorter, because a block that took six lines is now used in one. It becomes easier to correct, because a fix is made in a single place. And it becomes easier to read, because a line such as battery_report("Rover", 82) says plainly what is happening, while six lines of print and if statements make the reader work it out.
There is one honest limitation. A function only helps when a job is genuinely repeated or genuinely worth naming. Wrapping a single print statement inside a function of its own adds a name to remember without saving you anything. Use a function where it makes the program clearer, not everywhere.
16.2 Defining and Calling a Function
Using a function always happens in two separate steps, and it helps to keep them apart in your mind from the start.
The first step is writing the function down: giving it a name, saying what values it needs, and listing the instructions it should carry out. This is the function definition. Writing a definition does not make anything happen. It is like writing the sharbat recipe on a card — the card by itself does not make a drink.
The second step is using it. You write the function’s name and hand it the values it needs, and Python then runs the instructions inside. This is a function call. The recipe card is picked up and followed.
The general form
Every function definition in Python follows the same shape.
def function_name(parameters):
"""docstring"""
# function body
# code to execute
return expressionThe first line begins with the keyword def, followed by the name you are giving the function and a pair of round brackets. It ends with a colon. Everything that belongs to the function is written below it, indented. Sections 16.2.1 to 16.2.3 look at each part of this shape in turn.
A call is much shorter. You write the name and the round brackets, with the values inside:
function_name(values)The battery report, written once
In Section 16.1 the battery report for three robots was typed out three times. Here is the same job done with a function.
The output is exactly the same as before, but the report instructions now exist in only one place. Change 30 to 40 on that one if line, and all three robots are judged by the new limit at once. Adding a fourth robot takes one line, not six.
How Python moves through the program
Follow the order in which the lines actually run, shown in Fig. 16.2-1. Python reads the def line and the indented block below it, notes that a function called battery_report now exists, and moves on without running any of it. It then reaches the first call. At that point it jumps up into the function, runs the instructions there with name holding "Rover" and level holding 82, and comes back down to the line after the call. The same jump happens again for the second call, and again for the third.
Diagram
Fig. 16.2-1 – Two columns. Left column shows the program lines in order: the def battery_report(...) block drawn as one shaded box, then three call lines below it. Right column shows numbered arrows: arrow 1 from the top of the program past the shaded box labelled “definition read, not run”; arrow 2 from the first call up into the shaded box labelled “jump in”; arrow 3 back down to the next line labelled “return here”; the same pair of arrows repeated for the second and third calls.
Where the definition must go
Python must have read a function’s definition before it reaches a call to that function. In a simple program this means the def block is written above the lines that use it. If you call a function on line 3 and define it on line 10, Python stops with an error saying the name is not defined.
This is a real limit, and it shapes how programs are laid out. Most Python files put all the definitions at the top and the lines that actually do the work at the bottom.
16.2.1 The Structure of a Function Definition
A function definition has four parts, and each one is doing a particular job. Take a small robotics example and look at it piece by piece.
A wheeled robot moves forward by turning its wheels. One full turn of a wheel carries the robot forward by the distance around the wheel’s rim. So if you know how far the robot must travel, and you know that rim distance, you can work out how many turns the wheel needs. That calculation is worth naming.
def wheel_turns(distance_cm, circumference_cm):
turns = distance_cm / circumference_cm
return turnsThe four parts are labelled in Fig. 16.2.1-1.
Diagram
Fig. 16.2.1-1 – The two lines of the definition printed large, with four labelled callouts pointing to them: an arrow to def labelled “keyword: tells Python a function follows”; an arrow to wheel_turns labelled “function name”; an arrow to the brackets and the words inside labelled “parameters: the values the function needs”; an arrow to the colon labelled “colon ends the header line”; and a brace around the two indented lines below labelled “function body”.
The header line
The first line is called the header. It starts with the keyword def, which is short for “define”. This word tells Python that a function is being written, not ordinary instructions.
After def comes the name. You choose it, and the same rules apply as for variable names: letters, digits and underscores only, no spaces, and it cannot start with a digit. A name in lower case with underscores between words, such as wheel_turns, is the usual style in Python. Choose a name that says what the function does, because that name is what a reader will see everywhere else in the program.
Inside the round brackets you list the values the function needs in order to do its work. Each of these is a parameter — a name that stands for a value which will be supplied later, when the function is called. Here there are two parameters, distance_cm and circumference_cm. Inside the function they behave exactly like ordinary variables.
The header line ends with a colon, just as the header of an if statement or a loop does. The colon says that an indented block is coming next.
The function body
Everything indented below the header is the function body. These are the instructions Python runs whenever the function is called. The indentation is what marks them as belonging to the function; a line brought back to the left margin is outside the function again.
The body can be as long as it needs to be and can contain anything a normal program contains — calculations, if statements, loops, even calls to other functions.
The return statement
The last line of this function is return turns. A return statement sends a value back to the place where the function was called, and ends the function immediately. Nothing after it inside the function will run.
This is what makes a function useful as a piece of a bigger calculation. The call wheel_turns(120, 20) does not just do something quietly — it produces a value that you can store in a variable, print, or use in a further sum.
A function without a return statement is perfectly legal. The battery_report function in Section 16.2 had none — it printed its results and sent nothing back. The difference matters, and Section 16.8 looks at it properly.
16.2.2 Calling a Function
A definition sits quietly until something uses it. Calling a function is how you use it, and a call is short: the function’s name, followed by round brackets holding the values you are handing over.
The robotics club is buying parts. Four ultrasonic sensors at ₹250 each, and two motors at ₹180 each. The same small calculation — a count multiplied by a price — is needed for both, so it is worth writing once as a function.
Arguments: the values you hand over
The values written inside the brackets of a call are the arguments. In cost_of_items(4, 250) the arguments are 4 and 250.
It is easy to mix up arguments and parameters, so keep the two words apart by where they appear. A parameter is a name in the definition. An argument is a value in the call. When the call runs, each argument is copied into the matching parameter, and the function body then works with those names.
The matching is done by position. The first argument goes into the first parameter, the second into the second, and so on. So in cost_of_items(4, 250), count becomes 4 and price_each becomes 250.
Using what comes back
A call to a function that returns a value can be used anywhere a value can be used. In the program above the returned value is stored in a variable, which is the clearest way to do it when you need the value again later.
You can also use a call directly inside a bigger expression or inside another call:
print("Total bill Rs", cost_of_items(4, 250) + cost_of_items(2, 180))Python works out each call first, then adds the two results, then prints. This is shorter, but the earlier version with named variables is easier to read when the numbers mean different things.
Giving the wrong number of arguments
The number of arguments in the call must match the number of parameters in the definition. If you call cost_of_items(4) and leave out the price, Python stops and reports a TypeError, saying that one required positional argument named price_each is missing. Give too many, and it reports that the function takes 2 arguments but more were given.
This strictness is helpful rather than annoying. It catches a whole class of mistakes at the moment they happen, instead of letting the program run on with a missing value. Section 16.7 shows how default values let a function be called with fewer arguments on purpose.
16.2.3 The Docstring
Six months after you write a function, you will not remember what it expects or what it gives back. Somebody else reading your program will never have known. A function’s name helps, but a name can only say so much.
Python provides a place to write that explanation, right inside the function itself. A docstring is a piece of text placed as the very first thing in the function body, wrapped in triple quotes, that describes what the function does.
def safe_to_move(distance_cm):
"""Return True if the path ahead is clear.
distance_cm is the reading from the front ultrasonic sensor.
The robot may move only when nothing is within 20 cm.
"""
return distance_cm > 20Triple quotes — three double-quote marks, """ — are used because they let the text run over several lines. A one-line docstring is fine too, and is written on a single line between the same triple quotes.
The docstring is optional. Leave it out and the function works exactly the same. But it costs two lines to write and saves a great deal of guessing later.
What to put in it
Say what the function does, what each value it takes is meant to be, and what it gives back. Say it in plain sentences, not in code. The docstring above tells a reader three useful things: the answer is True when the path is clear, distance_cm comes from the front sensor, and the cut-off is 20 cm.
Do not describe how the function works line by line. That is what the code itself shows, and a step-by-step description goes stale the moment somebody edits the code.
With 35 cm ahead the path is clear, so the function returns True. With 12 cm the obstacle is inside the 20 cm limit, so it returns False.
Python can read it back to you
A docstring is not just a note for humans. Python stores it, and the built-in help() function prints it out. Add help(safe_to_move) to the end of the program above and you get:
Help on function safe_to_move in module __main__:
safe_to_move(distance_cm)
Return True if the path ahead is clear.
distance_cm is the reading from the front ultrasonic sensor.
The robot may move only when nothing is within 20 cm.
This is exactly how the help for Python’s own functions is produced. Try help(len) and you will see the same layout.
16.3 Built-in Functions
You have been calling functions since your very first Python program. print() is a function. So are input(), len() and int(). Nobody defined them in your file, yet they work the moment you type them.
They work because they come with the language. A built-in function is a function that is part of Python itself and is available in every program without any extra step.
That last part matters. Python also comes with a large collection of extra functions kept in separate files called modules — for example math.sqrt(), which finds a square root. Those are not built-in. You have to write an import line before you can use them. Built-in functions need no such line.
Some you will use often
Note what len() and sorted() have in common: they do not care much what kind of collection you hand them. len("robot") gives 5, and len([4, 9, 2]) also gives 3 items counted the same way. One function covers many kinds of data.
Putting several to work
A robot’s front sensor takes five distance readings as it crosses a room. The teacher wants a small report: how many readings there were, the nearest and farthest objects seen, the readings in order, and the average distance.
Every part of that report can be got from built-in functions. len() counts, min() and max() pick out the smallest and largest, sorted() arranges, sum() adds up, and round() tidies the average to two decimal places.
Not one line of that program says how to count a list, sort it or add it up. Those instructions exist, but somebody wrote them long ago and gave them names. That is the whole idea of a function, working at the scale of the language itself.
Two small ones worth knowing
abs() gives a number without its sign, which is useful whenever you care about how far off something is but not in which direction. If a robot was told to stop 30 cm from a wall and actually stopped at 26 cm, then abs(26 - 30) gives 4 — the error is 4 cm, whether it stopped short or overshot.
round() cuts a long decimal down to a sensible size. round(3.14159, 2) gives 3.14. Without a second value, round() gives the nearest whole number.
Built-in functions are fast, well tested and used by everyone, so prefer them over writing your own version of the same thing. But they only cover general jobs. No built-in function knows what your robot is meant to do, or how your school calculates a grade. For that you write your own, which is what Section 16.4 is about.
16.4 User-defined Functions
Python’s own functions handle general jobs — counting, sorting, rounding. They cannot handle the job in front of you, because nobody who built Python knew about your school’s grading rule or your robot’s wiring. For that you write the function yourself.
A user-defined function is a function you write with def to do a task your program needs.
The word “user” here means the person writing the program, not the person using it later.
One job, one function
The most useful habit in this whole chapter is to give each function one clear job, and let a bigger function call the smaller ones.
Take a school report. Turning marks into a percentage is one job. Turning a percentage into a grade is a second job. Printing a line for one student is a third, and it uses the first two. See Fig. 16.4-1.
Diagram
Fig. 16.4-1 – Three boxes. A large box on the left labelled report, with two arrows going out to smaller boxes on the right labelled percentage and grade. The arrow to percentage is labelled “marks in, percentage out”; the arrow to grade is labelled “percentage in, letter out”. A single arrow leaves report at the bottom to a small screen icon labelled “one printed line”.
Notice how short report is. It reads almost like an English sentence, because the two hard parts have names of their own. If the school later changes the grade bands, you edit grade and nothing else. If it changes how percentages are rounded, you edit report and nothing else.
The same function, used many times
The second big gain is reuse. Once a function exists, a loop can call it for every item in a collection.
Before a dataset can be used to train a model — a program built from data, which you will meet later in the course — the labels have to be tidied up. People type them inconsistently: extra spaces, capitals in odd places. " Cat ", "CAT" and "cat" all mean the same animal, but a program compares them letter by letter and treats them as three different labels.
One small function fixes all of them.
The function is two lines long and is called four times. With four hundred labels the program would be exactly the same length — only the list would grow.
There is a cost to all this, and it is worth naming honestly. Splitting a program into many small functions means a reader has to jump between them to follow one idea. A function used only once, with a vague name, usually makes a program harder to read rather than easier. Write a function when the job has a name worth giving it.
16.5 Built-in and User-defined Functions Compared
Both kinds of function are used in exactly the same way. You write the name, you put the values in brackets, and you get an answer back. Python does not treat them differently at the moment of the call, and nothing in a line of code marks one kind out from the other.
def robot_id(number):
return "RBT-" + str(number)
print(robot_id(7))
print(len(robot_id(7)))Output:
RBT-7
5
There are three functions at work in the last line. robot_id is one you wrote, str() and len() came with Python, and print() did too. They are called the same way and their results feed into each other freely.
The difference is not in how they are used. It is in where they come from and who can change them.
Which one to reach for
The answer is nearly always the same. If a built-in function already does the job, use it. It has been tested by millions of programmers, it is usually faster than anything you would write, and a reader recognises it at a glance.
Write your own when no built-in does what you need, or when a piece of your program deserves a name of its own. Those two reasons cover almost every function you will ever write.
16.6 Functions and Modularity
A robot is not built as one solid object. It has a mechanical block, an electronic block and a computational block, and each of those is made of parts that fit together. If a motor burns out, you replace that motor. Nobody rebuilds the chassis to fix a wheel.
Programs are built the same way, and for the same reason. Modularity means building something as a set of separate parts, each with its own job, that fit together to make the whole. In a Python program, functions are those parts.
Fig. 16.6-1 shows the difference in shape between a program written as one long stretch of code and the same program written as a set of functions.
Diagram
Fig. 16.6-1 – Two panels side by side. Left panel titled “One long program”: a single tall unbroken rectangle of code lines with a small red cross somewhere in the middle and a caption “a change anywhere means reading everything”. Right panel titled “Built from functions”: four small stacked boxes labelled days_late, fine, slip and “main program”, with arrows from “main program” to the others, and a small red cross inside only the fine box, captioned “a change stays inside one box”.
Five things modularity gives you
Encapsulation. A function keeps its working steps inside itself and shows the outside world only its name, the values it needs and the value it gives back. Whoever calls fine(5) does not need to know how the amount is worked out. Hiding the details this way is called encapsulation, and it is what lets you use a function you have not read.
Reuse. Once a function exists, it can be called from anywhere in the program, as many times as needed. The same code is not written twice, so it does not have to be maintained twice.
Readability. A program made of well-named functions can be read at the level of what it does before you go down into how. A line saying slip("Meera", 12, 17) tells you the point of it immediately.
Scalability. New work is added by writing a new function, not by threading extra lines through code that already works. A program can grow a great deal without becoming tangled.
Debugging. When something is wrong, modular code narrows the search. If the number of days is right but the amount is wrong, the mistake is inside fine and nowhere else. You have three lines to check instead of thirty.
Seeing it in a small program
The school library charges ₹2 for each day a book is late. Three separate jobs are hiding in that sentence: working out how many days late a book is, turning that number of days into an amount, and printing a slip for the student. Give each one a function.
Now suppose the school raises the charge to ₹3 a day. There is exactly one line to change — return days * 3 inside fine. The other two functions and the calls at the bottom stay untouched, because neither of them knows or cares what the rate is. That is encapsulation paying for itself.
Modularity is a habit, not a rule, and it can be overdone. Ten functions of two lines each, with names that do not mean much, are harder to follow than one clear function of fifteen lines. The test is whether each part has a job you can name in a few words.
16.7 Arguments Passed to a Function
You already know what an argument is: a value written inside the brackets of a call, which Python copies into the matching parameter before the function body runs. So far every call in this chapter has supplied its arguments in the same plain way — the right number of values, in the right order.
That is not the only way. Python offers a few different ways of handing values over, and each one exists to solve a real difficulty.
Think about a function that tells a robot to move:
def move(direction, speed, duration):Three values, and a call such as move("left", 30, 2) is easy to get wrong. Was 30 the speed or the duration? What if most moves happen at the same speed and typing it every time is a nuisance? What if a function has to accept a list of readings whose length you do not know in advance?
Each of those questions has an answer, and together they make up the rest of this section. See Fig. 16.7-1.
Diagram
Fig. 16.7-1 – A single box on the right labelled def move(direction, speed, duration): with three small slots drawn inside it. Four arrows come in from the left, each from a labelled tag: “positional — matched by order”, “keyword — matched by name”, “default — value already waiting in the slot”, and “variable length — one arrow that splits into many”. Each arrow points to the slots of the function box.
The ways of supplying arguments are:
- Positional arguments — matched to parameters by the order they are written in.
- Keyword arguments — matched by naming the parameter in the call.
- Default arguments — a value written into the definition, used when the caller supplies none.
- Variable length arguments — used when the number of values is not fixed in advance.
These are not four different kinds of function. They are four ways of calling and defining, and a single function can use more than one of them at the same time.
One rule runs through all four, and it is worth fixing in your mind before the details: the definition decides what values a function needs, and the call decides how those values are supplied. Sections 16.7.1 to 16.7.4 take each way in turn.
16.7.1 Positional Arguments
This is the ordinary way of passing values, and the one you have been using all through the chapter. A positional argument is matched to a parameter by where it appears in the call: first argument to first parameter, second to second, and so on.
Nothing in the call says which parameter a value belongs to. Its position says it.
The first call is right. In the second, the same three values were passed in a different order, and Python obediently put 30 into direction and "left" into speed.
Look closely at what did not happen. There was no error. Python does not know that a direction should be a word and a speed should be a number — those are meanings in your head, not rules in the code. It matched by position and carried on. On a real robot the instruction would be nonsense, and the fault would show up only in the robot’s behaviour.
Order matters, count matters
Two rules apply to positional arguments, and both are strict.
The number of arguments must equal the number of parameters. Give too few or too many and Python stops with a TypeError before the function body runs at all.
The order must match the definition. This one Python cannot check for you, which is why it is the more dangerous of the two.
Positional arguments are short to write and perfectly clear when a function takes one or two values whose meanings are obvious. len(readings) and abs(-4) need nothing more. It is the long calls, with four or five values of the same type, where position alone stops being enough.
16.7.2 Keyword Arguments
Position works well for short calls. It stops working well when a function takes several values that look alike, and the reader of the call has to remember which slot is which.
Python lets you name the parameter in the call itself. A keyword argument is an argument written as parameter_name=value, so Python matches it by name instead of by position.
All three calls do the same thing. The second one lists the values in a completely different order from the definition, and it still works, because each value carries the name of the parameter it belongs to.
Mixing the two styles
The third call above mixes both styles: one positional argument first, then two keyword arguments. This is allowed, but only in that order.
Every positional argument must come before every keyword argument. Once you have started naming, you cannot go back to relying on position, because Python would have no way of telling which slot the unnamed value was meant for.
When to use names
Use keyword arguments when a call would otherwise be hard to read. A call such as report_card(85, 90, 78, 92) tells a reader nothing, while naming each value makes the meaning obvious without looking up the definition.
They are also useful when a function has many parameters with default values and you want to change only one of them, which Section 16.7.3 shows.
The cost is length. len(readings) needs no name, and len(obj=readings) would only make it harder to read. Name a value when the name adds meaning, not as a habit.
16.7.3 Default Arguments
Some values are the same nearly every time. A scan usually runs at the same speed. A photograph in a dataset usually has no label yet. Typing that same value into every call is tedious, and the day you mistype it, the program quietly does something else.
Python lets the definition itself carry a value to fall back on. A default argument is a value written into the function definition, which is used when the caller does not supply one.
The general shape is:
def function_name(parameter1, parameter2=default_value):
# function bodyHere parameter1 must always be supplied by the caller. parameter2 need not be — if it is left out, the value written in the definition is used.
One default in action
Before a picture dataset can be used, every image needs a label saying what is in it. Labelling takes time, so images start out with no label at all and are filled in as people work through them.
The second call gives one argument where the definition has two parameters. That is not an error here, because label already has a value waiting for it.
Several defaults, and skipping one
A function can give defaults to more than one parameter. Combine that with keyword arguments and you can change just the one value you care about, leaving the rest alone.
The first call supplies nothing, so all three defaults are used. The second supplies one positional argument, which goes into the first parameter, steps. The third names direction and changes only that, leaving steps and speed at their defaults.
That third call is the reason keyword arguments and default arguments are so often used together. Without the name, there would be no way to skip past steps and speed to reach direction.
The one rule about order
Parameters with defaults must come after parameters without them.
Defaults make a function easier to call, but they also hide values from the reader of a call. Someone looking at scan_report() cannot see what speed was used without opening the definition. Give defaults to values that genuinely have a sensible normal setting, and leave the important ones for the caller to state.
16.7.4 Fixed and Variable Length Arguments
Every function so far has had a fixed number of parameters. move takes exactly three values, label_photo takes one or two. These are fixed arguments — the definition decides how many values the function accepts, and a call must fit that.
That is fine when the number is known in advance. It is a problem when it is not.
A robot takes distance readings as it crosses a room. On a short crossing it might take two. On a long one, twenty. You cannot write a definition with twenty parameters and hope, and you certainly cannot write a different function for every possible count.
For this Python offers variable length arguments — a way of letting a function accept any number of values, however many the caller happens to have.
Many values under one name
Put a star before a parameter name in the definition, and that parameter collects all the remaining positional arguments into a tuple.
The same function handled two readings, then four, then none at all. Inside the function, readings is an ordinary tuple, so a for loop can go through it and len() can count it.
The name readings is your choice, like any parameter name. It is the star that matters. You will often see the name args used, simply because that is the common habit, but any sensible name works.
Fixed and variable together
A definition can have ordinary parameters first and a starred one after. The fixed ones are filled from the left as usual, and everything left over goes into the starred parameter.
A second star, written as **, does the same job for keyword arguments: it collects any named values the caller supplies into a dictionary.
name is a fixed parameter and had to be supplied. Everything else arrived as keyword arguments and was gathered into extras, which the loop then went through.
Variable length arguments buy flexibility, and they cost clarity. A definition reading def f(*args): tells a reader nothing about what the function expects, and Python can no longer catch a call that supplies the wrong number of values. Use fixed parameters wherever the number of values is genuinely known, and keep the starred form for the cases where it truly is not.
16.8 Return Values and Return Types
A function that only prints is a dead end. Its answer goes to the screen and nowhere else, so no other part of the program can use it. A function that returns its answer hands it back to the caller, who can then store it, print it, or feed it into the next calculation.
That is what return does, and it does two things at once. It sends a value back to the place where the function was called, and it ends the function immediately.
Where the value goes
Look at what happens on the line answer = wheel_turns(120, 20) from Section 16.2.1. Python jumps into the function, runs it, meets return turns, and comes back carrying the value. At that moment the whole call is replaced by that value, and the assignment then stores it in answer.
So a call to a returning function can go wherever a value can go — on the right of an =, inside a print(), inside an if condition, or inside another call.
A function with no return
Not every function needs to send something back. battery_report from Section 16.2 printed its results and had no return at all. Such a function still gives something back, though — Python quietly returns the special value None, which stands for “no value here”.
def show(message):
print(message)
result = show("Robot ready")
print(result)Output:
Robot ready
None
The first line came from inside the function. The second is what result holds: None, because show never returned anything. This is worth knowing, because a None turning up unexpectedly in your program is almost always a call to a function you thought was returning a value.
The kinds of value a function can return
Python does not restrict what a function may return. Whatever kind of value your code can hold, a function can hand back.
The kind of value a function gives back is called its return type. Notice that Python does not state the return type anywhere in the definition. You find it by reading the return statements — one more reason to say it in the docstring.
Returning more than one value
A return can list several values separated by commas. Python packs them into a tuple and returns that one tuple.
The line p, a, pc = attendance(34, 40) takes the three values out of the returned tuple and puts them into three variables in one step. If you would rather keep them together, write figures = attendance(34, 40) and the whole tuple (34, 6, 85.0) is stored under one name.
More than one return statement
A function may contain several return statements, with only one of them running on any given call. The grade function in Section 16.4 works this way: whichever band the percentage falls into, that return runs and the function ends there.
This is a clear way to write a decision. Just make sure every path through the function reaches a return. If some branch of an if has none, that call returns None, and the caller receives nothing useful without any warning.
16.9 Summary
- Copying the same lines of code again and again makes a program long and unsafe to change, because every copy has to be corrected separately and a forgotten copy keeps running the old instructions.
- A function is a named block of code that carries out one particular task. It is written once and can be used as many times as needed.
- Using a function takes two steps. The function definition writes it down; the function call runs it. A definition on its own makes nothing happen.
- A definition begins with the keyword
def, then the function name, then the parameters in round brackets, then a colon. Everything indented below is the function body. - A parameter is a name in the definition. An argument is a value in the call. Arguments are copied into parameters when the call runs.
- A docstring is a description of the function written in triple quotes as the first line of the body. Python stores it, and
help()prints it out. - A built-in function comes with Python and is ready in every program without being defined or imported. Examples are
print(),len(),range(),abs(),round()andsorted(). - A user-defined function is one the programmer writes with
deffor a task the language does not already cover. Both kinds are called in exactly the same way. - Modularity means building a program from small parts, each with one clear job. Functions provide this, and bring encapsulation, reuse, readability, scalability and easier debugging.
- Positional arguments are matched to parameters by their order in the call. Getting the order wrong usually gives no error, only a wrong result.
- Keyword arguments are written as
parameter_name=valueand are matched by name, so their order does not matter. All positional arguments must come before any keyword arguments. - A default argument is a value written into the definition, used when the caller supplies none. Parameters with defaults must be listed after those without.
- Fixed arguments mean the definition decides how many values the function takes. Variable length arguments, written with a star before the parameter name, let a function accept any number of values.
- A return statement sends a value back to the caller and ends the function at once. A function with no return statement gives back
None. - A function can return a single value, a Boolean, a tuple, a list or a dictionary. Several values listed after
returnare packed into one tuple, which the caller can split across separate variables. - Functions are a tool, not a rule. Write one where a job has a name worth giving it, and prefer a built-in function whenever one already does what you need.
16.10 Key Terms
- Argument – a value written inside the brackets of a function call, which is copied into a parameter when the function runs.
- Built-in function – a function supplied by Python itself, usable in any program without defining or importing anything.
- Default argument – a value written into a function definition, used for that parameter when the call supplies none.
- Docstring – a description of a function, written in triple quotes as the first line of the function body, which
help()can display. - Encapsulation – keeping a function’s working steps inside it and showing the outside world only its name, the values it needs and the value it returns.
- Fixed arguments – arguments whose number is decided by the function definition, so every call must supply exactly that many.
- Function – a named block of code that carries out one particular task and can be used as many times as needed.
- Function body – the indented block of instructions below the
defheader, which runs each time the function is called. - Function call – the use of a function’s name with brackets in a program, which makes Python run the instructions inside it.
- Function definition – the block of code beginning with
defthat names a function and lists the instructions inside it. - Keyword argument – an argument written as
parameter_name=valuein a call, matched to its parameter by name rather than by position. - Model – a program built from data, which is used later to work something out from new data.
- Modularity – building a program as a set of smaller self-contained parts, each doing one clearly defined job.
- Parameter – a name listed in a function definition that stands for a value to be supplied when the function is called.
- Positional argument – an argument matched to a parameter by the order in which it appears in the call.
- Return statement – a statement beginning with
returnthat sends a value back to the caller and ends the function immediately. - User-defined function – a function written by the programmer with
defto carry out a task the language does not already provide. - Variable length arguments – a way of writing a parameter, with a star before its name, that lets a function accept any number of values.
16.11 Objective Questions
(Which keyword is used to begin a function definition in Python?)
definedeffunctionreturn
(Fill in the blanks: A name listed inside the brackets of a function definition is called a ____________, while a value written inside the brackets of a function call is called an ____________.)
(State whether true or false: Python runs the instructions inside a function as soon as it reads the function definition.)
(Which of these is a built-in function?)
percentage()battery_report()sorted()tidy()
(Match each item in Column A with its correct meaning in Column B.)
Column A Column B a. defi. Sends a value back to the caller and ends the function b. Docstring ii. Collects any number of positional arguments into a tuple c. returniii. The keyword that begins a function definition d. *readingsiv. A description of the function, written in triple quotes (What is the output of this program?)
def price(units, rate=8):
return units * rate
print(price(5))- (What value does a function give back if it has no
returnstatement?)0- An empty string
None- It gives an error
16.12 Concept Questions
(Define a function. State any two problems that writing a function solves in a long program.)
(Differentiate between a parameter and an argument. Use one short example of your own to show both.)
(A function is defined as
def timer(hours, minutes, seconds):. Explain why a call written with keyword arguments is easier to read than one written with positional arguments only.)(What would happen if a parameter with a default value were written before a parameter without one? Give a reason for your answer.)
(Write a function that takes a distance in metres and a time in seconds and returns the speed in metres per second. Show one call to your function and state the value it returns.)
(Explain how dividing a program into small functions makes it easier to correct a mistake. Support your answer with an example of a rule that might need to be changed later.)
16.13 Case-Based Questions
(The stationery counter of a school sells items at fixed rates. The record for one morning is shown below.)
Item Rate per unit (₹) Quantity sold Notebook 40 3 Pen 10 5 - Write a function named
amountthat takes a quantity and a rate, and returns the amount payable for that item. - Using your function, work out the amount for notebooks, the amount for pens, and the total bill for the morning. Show the calculation.
- Most days only pens are sold, always at ₹10. Explain how a default argument would shorten the calls, and write the changed
defline.
- Write a function named
(The robotics club checks the battery level of its four robots before every practice session. The readings taken one afternoon are shown below. A robot with a battery level below 25 percent must be charged before use.)
Robot Battery level (percent) Bot-A 68 Bot-B 21 Bot-C 45 Bot-D 12 - Name the built-in functions you would use to find how many readings were taken and which robot has the lowest battery level.
- Write a function named
needs_chargingthat takes a battery level and returnsTrueif the robot must be charged, andFalseotherwise. State the return type of your function. - The club later buys two more robots, so the number of readings changes from session to session. Explain how a variable length argument would let one function add up the readings for any session.