Python Functions

Learn to write your own functions in Python. Define and call functions, pass in values with parameters, keyword arguments and default values, and send results back with return. Find out which variables a function can see and change, describe your functions with docstrings, and break a program into small, well-named functions that you build and test one at a time.

BeginnerLesson 4 of 10 in Python for Beginners: Introduction to Programming

What you will learn

  1. Write a function with def, run it by calling it, and follow the order in which Python executes a program that contains functions.
    • Define a function and call it
      Write a function header and an indented body, choose a clear name, and run the function by calling it with parentheses.
    • Follow the flow of execution
      Trace the order in which Python runs statements when functions call other functions, and predict a program's output from that order.
  2. Use parameters and arguments to give a function the values it works on, matched by position, by name or through default values.
    • Use parameters and positional arguments
      Add parameters to a function header, pass matching arguments in a call, and read the errors that a wrong number of arguments produces.
    • Call functions with keyword arguments
      Pass arguments by parameter name, combine positional and keyword arguments in the right order, and fix the errors that wrong combinations cause.
    • Give parameters default values
      Make parameters optional with default values, order required and optional parameters correctly, and know when a default value is created.
  3. Use return to hand a value back to the code that called a function, tell returning apart from printing, and write functions whose results can be stored, tested and combined.
    • Return a value and use it
      End a function with return, use the returned value in variables and expressions, and see why returning a value is different from printing it.
    • Return from different paths and combine results
      Write functions with several return statements, return True or False, return early from a loop, return two values, and pass one function's result to another.
  4. Predict which variables a function can see and change, move data in and out through parameters and return values, and use global only when it is really needed.
    • Work with local variables and parameters
      Explain why variables created inside a function exist only during its call, how Python finds a name, and why changing a parameter does not change the caller's variable.
    • Use global variables with care
      Read global values safely, understand the error that assigning to a global name causes, use the global statement correctly, and prefer parameters and return values.
  5. Describe functions with docstrings, break a problem into small, well-named functions, and build and check a program one function at a time.
    • Document functions with docstrings
      Write one-line and multi-line docstrings that follow the common conventions, and read them with help().
    • Break a problem into functions
      Decompose a task into steps, turn each step into a function with clear inputs and outputs, and organize the program around a main function.
    • Build and check a program one function at a time
      Develop a program in small steps, test each function with inputs whose results you know, and use tracebacks and temporary prints to find bugs inside functions.

Python Functions study guide

5 chapters

1

Define and call your own functions

A function gives a useful piece of code a name, so you can run it whenever that job is needed. Writing the definition and making a call are separate actions, and that difference explains why some programs finish without showing anything. You will write correctly indented definitions, choose readable names, and follow execution as a function calls another function and then returns to its caller.

1.1 Define a function and call it

A function is a named block of code that does one job. Built-ins such as print() and input() already give you useful jobs to call; def lets you create your own. A good name turns several lines of work into a call that says what you want done.

Write the header and body
def greet():
    print("Hello!")
    print("Welcome to Python.")

greet()
greet()

The header starts with def, then the name, parentheses and a colon. The indented lines form the body. Use four spaces for each indentation level. The unindented greet() lines are outside the function, so they are calls in the main program.

When Python reaches the definition, it creates the function and gives it the name greet. It does not print either message yet. The first call starts at the first body line and prints "Hello!" followed by "Welcome to Python." The second call starts the body again and prints the same two lines. There are four output lines in all.

A name and a call are different

The parentheses in greet() make it a call, even though this function needs no inputs. A line containing only greet refers to the function and runs nothing. print(greet) displays a description of the function object, including a memory address; it does not run the greeting.

Python must have executed a definition before a call uses its name. If a file starts with greet() and defines greet afterward, the first line raises NameError: name 'greet' is not defined. Put the definition above the top-level call.

Choose names that explain the job

Use lowercase words joined by underscores, such as print_receipt or convert_to_miles. Names may contain letters, digits and underscores, but cannot start with a digit or be a reserved word such as return. Names are case-sensitive: greet and Greet are different names.

Keep built-in names available. After input = "yes", the name input refers to text, so input("Name? ") raises TypeError: 'str' object is not callable. Naming the variable answer keeps the built-in accessible.

Repair the structure first

A missing header colon produces SyntaxError: expected ':'. An empty body or a body with no indentation produces an IndentationError. A planned function still needs a statement; pass is a placeholder that does nothing:

def print_receipt():
    pass

print_receipt()

This program runs without output. The call reaches pass and then the end of the body. Replace the placeholder with the real job when you are ready to implement it. If a line was meant to belong to the body but runs at the wrong time, check its indentation before changing the call.

Key Takeaways

  • Use def name(): and an indented body to define a function.
  • A definition creates the function; parentheses make a call that runs it.
  • Execute a function's definition before making a call that needs its name.
  • Choose descriptive lowercase names with underscores and avoid built-in names.
  • Use pass when a planned function needs a valid placeholder body.

1.2 Follow the flow of execution

A program with functions does not run every body in the order it appears on the page. A call changes the flow of execution: Python enters the called function, finishes its work, and resumes the caller just after that call.

Follow a call into another call
def line():
    print("----------")

def banner():
    line()
    print("  REPORT")
    line()

print("Start")
banner()
print("End")

First, Python defines line and banner. Neither body runs. The next statement prints "Start". The call to banner() enters its body, whose first statement calls line().

Python now enters line, prints "----------", and reaches its end. It returns to the next statement in banner, which prints " REPORT". The second line() call prints another dashed line. Finally, banner ends, so the main program resumes and prints "End".

The output is:

Start
----------
  REPORT
----------
End
Keep track of unfinished calls

While line runs, banner is waiting for it to finish. The main program is also waiting for banner. Python records these unfinished calls in the call stack. The innermost active call finishes first, and each caller resumes at its own next statement.

For a paper trace, number the program's lines. Record a body line only when execution reaches it through a call. At every call, mark where to resume. Write output when its print runs, keeping spaces and line breaks. This separates the path through the code from the output it produces.

Define helpers before they are needed

The helper's definition may appear below the caller's definition:

def show_report():
    draw_line()
    print("Ready")

def draw_line():
    print("====")

show_report()

This works because both definitions have run before the final call enters show_report. Python looks up draw_line when the body actually calls it. Moving show_report() above def draw_line(): would make the call fail when it tries to use the missing helper.

Repeated calls start fresh

A call inside a loop enters the body on each repetition:

for i in range(3):
    line()

Using the first line definition, this prints the dashed line three times. The function begins at its first body statement for every call.

If a call fails, Python shows a traceback. Its last line gives the error type and message. The call entries above it run from the outermost unfinished call down to the line that failed. Reading the final error first, then checking the innermost line and its caller, helps you locate both the failing operation and the route that supplied its data.

Key Takeaways

  • Trace body statements in call order, recording output when each print runs.
  • The call stack keeps track of unfinished calls and where to resume.
  • A helper can be defined below its caller if its definition runs before it is called.
  • Read a traceback's final error and then inspect the failing line and its caller.
2

Pass information into functions

Parameters let one function handle different inputs without rewriting its body. The caller supplies arguments, and Python connects those values to the parameter names before the body starts. You will match arguments by position and by name, combine these forms correctly, and choose defaults for common cases. You will also see why a default is created when the definition runs and how that affects a list used as a default.

2.1 Use parameters and positional arguments

A function becomes reusable across different inputs when its header names the values it needs. These names are parameters. The caller supplies arguments, which are the actual values used for a particular call.

Match values to names
def rectangle_area(width, height):
    print("Area:", width * height)

rectangle_area(4, 2.5)
rectangle_area(3, 7)

The parameters are width and height. In the first call, the arguments are 4 and 2.5. Positional arguments match from left to right: width receives 4 and height receives 2.5. The body prints "Area: 10.0". The next call gives the same parameter names new values and prints "Area: 21".

Each parameter acts as a variable inside that call. You do not need to assign width and height beforehand; the call supplies them. A function without parameters still needs empty parentheses in both its definition and its calls.

Order can change the meaning
def describe_pet(animal, name):
    print(name, "is a", animal)

describe_pet("cat", "Milo")
describe_pet("Milo", "cat")

The first call prints "Milo is a cat". The second prints "cat is a Milo". Both calls are valid Python, so no error flags the swapped meaning. Read the header's order before choosing positional arguments, especially when several parameters accept the same kind of value.

Arguments can be expressions

Python evaluates each argument expression before the body starts. With side = 6, the call rectangle_area(side, side) passes 6 twice and prints "Area: 36". The caller's variable name does not have to match either parameter name. The call rectangle_area(side + 1, 2) passes 7 and 2; it does not pass the text "side + 1".

Read an argument-count error

Every parameter without a default needs an argument. With the area function above:

CallWhat goes wrong
rectangle_area(4)height is missing.
rectangle_area(4, 2, 1)Three arguments were given for two parameters.

The first raises TypeError: rectangle_area() missing 1 required positional argument: 'height'. The second raises TypeError: rectangle_area() takes 2 positional arguments but 3 were given. Check the named function's header, then count how the call fills its parameters.

Pass the kind of value the job needs

Python does not enforce a type simply because a parameter is named width. rectangle_area("4", 2) prints "Area: 44", because multiplying text by an integer repeats that text. Since input() returns text, convert numeric input before passing it:

width = float(input("Width: "))
rectangle_area(width, 2)

Here float() turns the entered text into a number before the area function receives it.

Key Takeaways

  • A parameter is a name in the header; an argument is a value supplied by a call.
  • Positional arguments fill parameters from left to right.
  • Python evaluates argument expressions before the function body runs.
  • Every required parameter needs a value; missing or extra arguments raise TypeError.
  • Convert numeric input from text before passing it to numeric work.

2.2 Call functions with keyword arguments

A keyword argument names its destination parameter in the call. This makes a call easier to read when several values could be confused. Python matches the keyword to the header's name instead of using its position.

Match by name
def describe_pet(animal, name):
    print(name, "is a", animal)

describe_pet(name="Milo", animal="cat")
describe_pet(animal="cat", name="Milo")

Both calls print "Milo is a cat". The order of keyword arguments can change because each value names the parameter it fills. The same idea makes rectangle_area(width=4, height=2.5) readable without checking which dimension came first.

A keyword is not a new variable in the calling code. In describe_pet(name="Milo", animal="cat"), name= directs "Milo" to the parameter. It does not assign "Milo" to a top-level variable called name. Write keyword arguments without spaces around =, following Python's usual style.

Combine positional and keyword arguments
describe_pet("cat", name="Milo")

The first argument fills animal by position. The keyword fills name, so every parameter receives exactly one value. Positional arguments must come first. The call describe_pet(name="Milo", "cat") is rejected with SyntaxError: positional argument follows keyword argument.

To inspect a mixed call, fill the positional slots from left to right, then match the keywords. Check that no slot is filled twice and no required slot remains empty.

Fix duplicate or unknown keywords
CallDiagnosis
describe_pet("cat", animal="dog")animal gets both "cat" and "dog".
describe_pet(animal="cat", nmae="Milo")The header has no parameter called nmae.

The duplicate raises TypeError: describe_pet() got multiple values for argument 'animal'. The misspelling raises TypeError: describe_pet() got an unexpected keyword argument 'nmae'. Compare names character by character; uppercase and lowercase letters matter too. Changing argument order does not repair a duplicate assignment to one parameter.

Recognize keywords in built-ins
print("a", "b", "c", sep="-")
print("Loading", end="...")
print("done")

The first line prints "a-b-c". sep supplies the text between the displayed values. The next two calls produce "Loading...done" on one line: end replaces the usual newline after "Loading".

Some built-ins accept named arguments too; for example, round(3.14159, ndigits=2) gives 3.14. Use the parameter names documented for the function you are calling. A descriptive word you invent is not recognized just because it seems to fit the job.

Key Takeaways

  • Keyword arguments match parameter names, so their order can vary.
  • Put positional arguments before keyword arguments.
  • Fill each parameter exactly once and spell every keyword exactly.
  • A keyword in a call directs a value; it does not assign a caller variable.
  • For print, sep controls separators and end controls the ending.

2.3 Give parameters default values

A default value lets a call omit an argument when a common choice is suitable. Write the default beside its parameter in the header. Supplying an argument overrides the default for that call.

Make a parameter optional
def greet(name, greeting="Hello"):
    print(greeting + ",", name + "!")

greet("Ana")
greet("Ana", "Welcome")
greet("Ana", greeting="Hi")

The output is "Hello, Ana!", "Welcome, Ana!" and "Hi, Ana!". name is required because it has no default. greet() therefore raises a TypeError, even though the other parameter is optional.

In these headers, required parameters come before parameters with defaults. def greet(greeting="Hello", name): is invalid. Python reports a syntax error about a parameter without a default following one with a default. Move name before greeting to keep it required.

Change one optional choice
def order_coffee(size, shots=1, milk="none"):
    print(size, "coffee,", shots, "shot(s), milk:", milk)

order_coffee("large", milk="oat")

This prints "large coffee, 1 shot(s), milk: oat". The keyword reaches milk while shots keeps 1. A positional call order_coffee("medium", 2) changes shots and leaves milk at "none". Positional matching does not skip an optional parameter to reach the next one.

Built-ins also offer defaults: ordinary print() separates values with a space and ends with a newline. round(3.7) gives the whole number 4; round(3.14159, 2) requests two decimal places and gives 3.14.

Defaults are created when the definition runs
rate = 0.05

def price_with_tax(price, tax_rate=rate):
    return price * (1 + tax_rate)

rate = 0.08
print(price_with_tax(100))
print(price_with_tax(100, rate))

The default stores the value 0.05 when def runs. Changing rate later does not change that stored default. The calls print "105.0" and "108.0": only the second explicitly supplies the new rate.

Avoid sharing a list by accident

A list holds items, and append adds an item to that same list. With a list default, calls that omit the argument all share it:

def add_item(item, basket=[]):
    basket.append(item)
    print(basket)

add_item("apple")
add_item("pear")

This prints ['apple'] and then ['apple', 'pear']. The default list was made once, not once per call. To make a fresh list for each omitted argument, use None as a signal:

def add_item(item, basket=None):
    if basket is None:
        basket = []
    basket.append(item)
    print(basket)

Now those two calls print ['apple'] and ['pear']. An explicitly supplied list is still used as given. Describe optional parameters and their defaults in the docstring so callers know which values omission selects.

Key Takeaways

  • An omitted optional argument uses its default; an explicit argument overrides it.
  • Place required parameters before parameters with defaults.
  • Use a keyword to change a later option without filling earlier optional slots.
  • Default expressions are evaluated once when def runs.
  • A mutable list default is shared by calls that omit it.
  • Use None and create a list in the body when each omitted argument needs a fresh list.
3

Send results back with return values

A calculation becomes more useful when its result can feed another calculation, a condition or a display. The return statement makes that possible by handing a value back to the caller. You will separate returning from printing, trace the first return that runs, and check paths that might end without a useful result. Then you will build Boolean functions, finish searches correctly and combine the results of small functions.

3.1 Return a value and use it

A function can give the caller a result to use. The return statement ends the call and sends its value back. At the calling point, the call stands for that returned value.

Store and combine results
def rectangle_area(width, height):
    return width * height

area = rectangle_area(4, 2.5)
print(area)
print(rectangle_area(3, 4) + rectangle_area(2, 5))

The first call returns 10.0, which is assigned to area; the first print displays it. In the final line, the two calls return 12 and 10. Python adds those results and prints "22". The function itself contains no print, so it can supply either a saved result or part of a larger calculation.

A returned value can also be tested in a condition or passed to another function. This separates the calculation's job from the caller's decision about how to use the answer.

Printing and returning have different jobs
def double_print(n):
    print(n * 2)

result = double_print(5)
print(result)

The call displays "10", but that displayed number is not sent back as the result. double_print reaches the end of its body, so it returns None. The last line therefore prints "None".

OperationWhere the value goes
print(value)Displays it for a person.
return valueSends it to the caller for the program to use.

double_print(5) + 1 first prints "10", then raises TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'. Replace the body with return n * 2 when the caller needs the doubled number. A function intended only to produce an effect, such as displaying a message, can appropriately return None; such functions are sometimes called void. A function with a useful returned result is sometimes called fruitful.

Stop at the first executed return
def to_fahrenheit(celsius):
    return celsius * 9 / 5 + 32
    print("Converted")

print(to_fahrenheit(20))

This prints "68.0". The print inside the body is never reached because return already ended the call. Remove that unreachable statement, or move a necessary action before the return. The conversion returns floats because / produces a float. Inputs 100 and -40 give 212.0 and -40.0.

A bare return with no expression also ends a call, returning None. Every function call has a result even when no useful value was supplied.

Make results visible in a program file

A standalone rectangle_area(3, 4) computes 12 and then discards the unused result in a file. Use print(rectangle_area(3, 4)) to display it or assign it to a variable. The interactive shell displays expression results except None, so a successful shell trial can look different from running the same line in a file.

Key Takeaways

  • return value ends the call and makes the call stand for that value.
  • Printing displays a value; returning makes it available to the caller.
  • Reaching the body's end or using a bare return gives None.
  • Statements after an executed return do not run in that call.
  • Use a returned result by storing, printing, testing or combining it.

3.2 Return from different paths and combine results

Different inputs may need different answers. A function can have several return statements, but a call stops at the first one it executes. Follow the actual path through its branches and loops to find the result.

Order overlapping tests
def letter_grade(score):
    if score >= 90:
        return "A"
    if score >= 80:
        return "B"
    if score >= 70:
        return "C"
    return "F"

For 85, the first test is false and the second is true. The function returns "B" without testing the remaining conditions. For 42, all three tests are false, so the final return supplies "F". Separate if statements work because each successful branch ends the call.

The highest threshold must be checked first here. If score >= 70 came first, a score of 95 would return "C". With overlapping ranges, an early broad match can hide a later, more specific answer.

Cover the path with no matching branch
def sign(n):
    if n > 0:
        return "positive"
    elif n < 0:
        return "negative"
    return "zero"

The final line handles zero. Without it, sign(0) would reach the end and return None. Trace an input from each branch and any remaining case; testing only positive and negative inputs would miss this gap.

Return a Boolean comparison
def is_even(n):
    return n % 2 == 0

if is_even(10):
    print("Even")

The comparison already produces True or False. is_even(10) returns True, while is_even(7) returns False. Use the result directly in a condition. An extra == True does not help the test.

Finish a search before reporting no match
def smallest_divisor(n):
    for d in range(2, n):
        if n % d == 0:
            return d
    return n

For 91, candidates 2 through 6 fail, then 7 divides it evenly. Returning 7 ends both the loop and the function. For 13, the loop finds no divisor, so the final return gives 13.

A test for primality needs to allow the search to continue after a failed candidate:

def is_prime(n):
    if n < 2:
        return False
    for d in range(2, n):
        if n % d == 0:
            return False
    return True

The final True is outside the loop. Putting it in an else inside the loop would return after checking only the first candidate: 9 would wrongly be accepted because it is not divisible by 2. With the corrected function, 9 and 1 return False; 2, 7 and 97 return True. For 2, the loop has no candidates, and execution reaches the final True.

Send back two values
def share(total, people):
    return total // people, total % people

each, left = share(17, 5)
print(each, left)

The call returns one tuple, a grouped result containing 3 and 2. Assignment unpacks it into two names, so the output is "3 2". Printing the call directly would show "(3, 2)". The number of names must match the number of values being unpacked.

Combine calls from the inside out
def add(a, b):
    return a + b

def to_fahrenheit(celsius):
    return celsius * 9 / 5 + 32

print(to_fahrenheit(add(10, 15)))

add first returns 25. That becomes the argument to to_fahrenheit, which returns 77.0. Finally, print displays "77.0". Each inner call must return the value the next function needs.

Key Takeaways

  • The first executed return ends a call, so order overlapping tests carefully.
  • Include a useful result for every input path the function must handle.
  • A Boolean function can return a comparison directly.
  • Inside a search loop, return a found result; report no match after all candidates fail.
  • Comma-separated returned values form one tuple that can be unpacked.
  • In nested calls, the inner result becomes the outer call's argument.
4

Know where variables live: local and global scope

A name inside a function may look identical to a name outside it while referring to a separate variable. Scope tells you where a name can be used, and assignment helps determine which name Python means. You will track parameters and other local variables through a call, distinguish reassignment from changing a shared list, and read global settings. You will also repair a common scope error and make changing values explicit in calls.

4.1 Work with local variables and parameters

Scope describes where a name can be used. Parameters and names assigned inside a function are local to that function's call. A caller and a function can use similar names without sharing the same local variables.

Keep local names inside their call
def make_greeting():
    message = "Hi"
    print(message)

make_greeting()

This prints "Hi". Adding print(message) after the call raises NameError: name 'message' is not defined: the local name is not available there. To make the value available to the caller, return it and store it:

def make_greeting():
    return "Hi"

message = make_greeting()
print(message)

The top-level message is a new caller variable receiving the returned value. The function does not make its own local names visible outside.

Each call gets fresh locals. If a body sets count = 0, adds 1 and prints it, two calls print "1" and "1". The second call does not continue with the first call's count. Different functions can also use local names such as total independently.

Follow shadowing and lookup
x = 10

def show():
    x = 5
    print(x)

show()
print(x)

The output is "5" then "10". The local x shadows the global x inside show; the assignment does not change the top-level value. A global variable belongs to the file's top-level scope. Ordinary assignments outside functions create globals.

For a function defined at the file's top level, Python looks for a name in its local names, then the file's globals, then built-ins such as print. The first match wins. Local and global names are therefore different places to check when a value seems wrong.

Reassigning a parameter leaves the caller's name alone
def add_bonus(points):
    points = points + 10
    print(points)

score = 50
add_bonus(score)
print(score)

points begins with the value 50. Its local reassignment makes it 60, so the first output is "60". The caller's score is still 50. To update that name explicitly, use a function that returns points + 10, then write score = add_bonus(score).

Changing a list is a different operation

A list can be shared through two names:

def add_guest(guests, name):
    guests.append(name)

party = ["Ana"]
add_guest(party, "Ben")
print(party)

The parameter guests and caller variable party refer to the same list. append changes that list's contents, so the output is "['Ana', 'Ben']". Assigning guests = [] inside the function would instead point only the local name at a new list; party would still refer to the original. When tracing a list argument, ask whether the line changes the shared object or only reassigns a local name.

Key Takeaways

  • Parameters and names assigned inside a function are local to its call.
  • Each call gets fresh locals; return values carry results out.
  • A local name can shadow a global without changing the global value.
  • Reassigning a parameter leaves the caller's variable unchanged.
  • Mutating a shared list changes the list seen by the caller.

4.2 Use global variables with care

A function can read a global name without a declaration. Assigning to a name in its body follows a different rule, and confusing these operations is a common source of UnboundLocalError.

Read a fixed setting
TAX_RATE = 0.25

def tax(amount):
    return amount * TAX_RATE

print(tax(80))

The output is "20.0". amount is local; TAX_RATE is read from the file's globals. Capital letters mark a constant by convention, signaling that the program should leave the setting fixed. Python does not enforce that convention.

Assignment makes a name local throughout the body
total = 0

def add_to_total(amount):
    total = total + amount

add_to_total(5)

The assignment makes total local throughout add_to_total. To calculate the right-hand side, Python tries to read that local name before it has a value. It does not fall back to the global total. The call raises UnboundLocalError: cannot access local variable 'total' where it is not associated with a value.

The decision is based on the whole body, not just lines already executed. A body with print(count) followed by count = 10 also treats count as local at the print line. A global count cannot supply the missing local value.

Declare a deliberate global assignment
total = 0

def add_to_total(amount):
    global total
    total = total + amount

add_to_total(5)
add_to_total(7)
print(total)

Now both the read and assignment refer to the global name, so the output is "12". Put global total before any use of total in the function. Using the name before its declaration is a syntax error.

A declaration alone does not create a value. A subsequent assignment can create a global that did not exist: a function body containing global level and then level = 1 creates the global level when called.

Show the change through inputs and a result

The same running total can be written with an explicit interface:

def add_to_total(total, amount):
    return total + amount

total = 0
total = add_to_total(total, 5)
total = add_to_total(total, 7)
print(total)

This also prints "12". Each call shows the old value being passed in, and the assignment shows where the new value goes. You can check add_to_total(10, 3) on its own without first setting up hidden global state. Several functions changing the same global make their behavior depend on the order they run.

Operation inside a functionDeclaration needed?
Read a global settingNo.
Reassign a global nameglobal name before use.
Append to an existing global listNo; the name is not reassigned.

Reading a shared list and changing its contents uses the existing reference. Replacing that global name with a different list is an assignment, so the assignment rule applies.

Key Takeaways

  • Read a global name without a special declaration.
  • Assignment anywhere in a function makes that name local unless declared global.
  • A read of an unassigned local raises UnboundLocalError.
  • Place global name before using a name that the function deliberately reassigns globally.
  • Prefer parameters and return values when a changing value can be passed explicitly.
  • Mutating a list and reassigning its name follow different rules.
5

Document and design programs with functions

Good functions need clear jobs as well as correct code. A caller should be able to see what a function needs, what it returns and any effect it has without studying every line of its body. You will write docstrings, divide a complete program into helpers, and connect them through a small main function. You will then check one piece at a time with expected results, boundary inputs and the clues in a traceback.

5.1 Document functions with docstrings

A caller needs to know a function's job without reading all its implementation. A docstring supplies that description. Python recognizes a string as the function's docstring when it is the first statement in the body.

Write a short description first
def to_fahrenheit(celsius):
    """Convert a temperature from degrees Celsius to degrees Fahrenheit."""
    return celsius * 9 / 5 + 32

print(to_fahrenheit.__doc__)

The output is the sentence inside the quotes. Python stores the docstring in __doc__; the triple quotes are not part of the stored sentence. help(to_fahrenheit) displays the description together with the signature to_fahrenheit(celsius). Pass the function name to help, without calling the function.

The common convention is triple double quotes, even for a one-line docstring. Start with a command such as "Return the area of a rectangle." and end with a period. Keep a short description and its closing quotes on one line. You do not need to repeat the function name and parameter list because the help display already includes them.

Add detail when callers need it
def split_bill(total, people, tip_rate=0.2):
    """Return each person's share of a bill, including the tip.

    total: the bill before the tip
    people: the number of people sharing the bill
    tip_rate: the tip as a fraction of the bill (default 0.2)
    """
    return total * (1 + tip_rate) / people

The first line states the result. A blank line separates it from details about the inputs. The default is documented as 0.2, a fraction of the bill; this prevents a caller from treating 20 as the intended value for a 20 percent tip. The closing quotes of a multi-line docstring go on their own line.

For split_bill(84, 4), the function applies the default tip and returns 25.2. A caller can learn what the three inputs mean before choosing arguments. Include units when they matter and describe effects such as printing, so a caller can predict both the result and visible behavior.

Keep documentation distinct from comments
FormMain purpose
First string in the bodyDescribes the function for its caller and appears in help.
# comment in the bodyExplains a code detail to someone reading the implementation.

A string placed after an assignment or another body statement is not the function's docstring. It is an unused string expression, and __doc__ is None if no first-statement docstring exists. A # comment also does not become the help description.

Write the summary while deciding the function's job. If the sentence needs several unrelated actions, reconsider whether the function should be split. When you change parameters, defaults, returned values or printed effects, update the docstring at the same time; callers rely on it as part of the interface.

Key Takeaways

  • A function docstring is the first statement in its body.
  • Use triple double quotes and a short command sentence ending with a period.
  • For longer descriptions, separate the summary from details with a blank line.
  • Describe meaningful inputs, units, defaults, results and effects.
  • Read stored documentation with help(name) or name.__doc__.

5.2 Break a problem into functions

Decomposition means splitting a task into smaller jobs. Each function takes responsibility for one job, with clear inputs and a clear result or effect. The main program can then read as a short sequence of named steps.

Plan the data before writing the bodies

For a program that reports an average test score and a letter grade, identify three kinds of work: read scores, calculate an average, and choose a grade. Decide what each helper receives and returns. Keep the display in main, where the results come together.

def get_score(prompt):
    return float(input(prompt))

def average(a, b, c):
    return (a + b + c) / 3

def letter_grade(score):
    if score >= 90:
        return "A"
    if score >= 80:
        return "B"
    if score >= 70:
        return "C"
    return "F"

def main():
    first = get_score("Test 1: ")
    second = get_score("Test 2: ")
    third = get_score("Test 3: ")
    avg = average(first, second, third)
    print("Average:", round(avg, 1), "Grade:", letter_grade(avg))

main()

With scores 78, 92 and 85, average returns 85.0. That result becomes the argument to letter_grade, which returns "B". The display is "Average: 85.0 Grade: B".

main coordinates the sequence; it does not need to know how letter_grade chooses its answer. Using a function through its job and interface, without following every body statement, is procedural abstraction. You already use print in this way.

Give the caller a clear interface

A function's interface consists of its name, parameters, returned result and documented behavior. average(a, b, c) requires three numbers and returns their average. Its caller does not have to read a prompt or capture printed text to obtain that number. You can rewrite the calculation while keeping its agreed inputs and output, and existing calls still work.

Use names such as calculate_total and print_receipt for actions, and is_even or has_discount for Boolean questions. Parameter names such as price and quantity explain what values belong in each slot. One-letter names can be suitable when their meaning is clear, as in the three inputs to average.

Turn repetition into parameters

If several parts of a program print different titles between the same lines of equals signs, make the title a parameter to print_heading(title). The repeated structure belongs in one body, while the varying text belongs in the calls. A later change to the line length then needs only one edit.

Choose function boundaries that make jobs easier to understand or reuse. Putting every statement into one long main hides the smaller jobs. Splitting every trivial expression into a helper used once can add names without improving readability. A useful test is whether a short sentence can describe each job and its inputs and outputs.

Finish the file with the actual main() call after all definitions. A program containing only definitions will create its functions and finish without running their bodies.

Key Takeaways

  • Decompose the task into jobs with named inputs and outputs.
  • Keep calculations separate from input and printing when they need to be reused or checked.
  • Let main coordinate helpers and call main() after the definitions.
  • Use parameters for the parts that vary in repeated code.
  • A stable interface lets callers use a function without depending on its body.
  • Choose function boundaries that make the program easier to understand.

5.3 Build and check a program one function at a time

Building several functions before running any of them makes a failure harder to locate. Incremental development means writing a small piece, checking it, then adding the next piece. You keep a working program while narrowing the amount of new code to inspect.

Use a stub while planning

A stub has the intended header and a placeholder body. A docstring and pass keep the definition valid, but the function returns None until you implement it. A fixed return can help exercise a caller's display without claiming the real calculation works yet.

Start with a calculating helper whose result you can work out independently. Once it behaves correctly, connect it to the next helper. Leave interactive input until the calculations can be checked with direct calls.

Decide expected results before running

Using the average and letter_grade functions, scores 70, 75 and 72 have an average of about 72.33, so their expected grade is "C". Check both stages:

print(average(70, 75, 72))
print(letter_grade(average(70, 75, 72)) == "C")

The outputs are "72.33333333333333" and "True". The comparison tests the expected grade directly; looking only at a program's own output without an independent expectation can let a plausible wrong answer pass.

Test edges as well as ordinary inputs

For a threshold of 90, test 90 and 89.9. The correct grade function returns "A" and "B". If its first condition were score > 90, only the exact-boundary check would reveal that 90 incorrectly falls through.

Include a typical value, exact boundaries, nearby values and extreme inputs that the function is meant to handle. For the grade function, checking 70 and 0 exercises the lowest passing boundary and the final "F" path. A check such as print(letter_grade(85) == "B") is easy because the function takes a value and returns its result.

Read the traceback and inspect the arriving value

Suppose main calls letter_grade(input("Score: ")). Entering "85" sends a string into a comparison with a number. The final error is TypeError: '>=' not supported between instances of 'str' and 'int'. The traceback points to the comparison inside the helper, while an earlier call line points to main.

The failure happens at the comparison, but the repair belongs where the input is prepared: convert it with float() before passing it. A temporary first-line print("letter_grade got", score) helps reveal an unexpected input. If its type is unclear, inspect the caller and the conversion it uses. Remove debug prints after the bug is fixed.

Connect symptoms to likely causes
SymptomCheck
A result is NoneA missing return or an uncovered path.
No effect appearsA missing call, or an unused returned result.
A plausible result has the wrong meaningSwapped arguments.
NameErrorA misspelled or unavailable function or variable name.

After repairing a helper, rerun the checks that exercise its affected paths and the caller that connects it to the program.

Key Takeaways

  • Build and check one function before adding the next.
  • Work out expected results independently before comparing them with calls.
  • Test exact boundaries and nearby values to catch comparison mistakes.
  • Use the traceback to find the failure and its callers.
  • Remove temporary debug prints once the problem is fixed.

Python Functions examples

5 Walkthroughs

1

Write a function and trace its calls

10 steps
Build a reusable greeting, then follow a caller through its helper and back to the main program.
  1. 1
    IntroductionGive a job a name

    A function lets you write a useful job once and choose when to run it. You will begin with a greeting, then trace a report that calls a helper.

    Keep two questions separate as you read: "Has Python created this function?" and "Has the program called it yet?" The first makes the name available; the second starts the body's work. This distinction explains why a file full of definitions can finish without output.

  2. 2
    ExplanationWrite the reusable body
    def greet():
        print("Hello!")
        print("Welcome to Python.")
    

    The header uses def, a name, parentheses and a colon. The two lines indented by four spaces form the body. Python creates the function when this definition runs, but neither print runs yet.

    The next unindented statement will be outside the function. Indentation tells Python where this job ends; it is part of the program's structure.

  3. 3
    ExampleRun it twice

    Add these lines after the definition:

    greet()
    greet()
    

    The first call enters the body and prints "Hello!" followed by "Welcome to Python." The second call begins at the first body line again and prints both messages again. There are four output lines.

    The empty parentheses still matter: greet alone refers to the function object. It does not call it, and print(greet) displays a function description instead of the greeting.

  4. 4
    ChallengePredict a missing call

    What does this file display?

    def ready():
        print("Ready")
    
    ready
    print("Waiting")
    

    ---reveal---

    It displays only "Waiting". The definition creates ready, and the name on its own refers to that function without running it. To display the message too, change ready to ready(). The call would then run before the final print, giving "Ready" and "Waiting" on separate lines.

  5. 5
    TipKeep names and bodies usable

    Use names such as print_receipt: lowercase words joined by underscores that describe the job. Avoid replacing a built-in name. Assigning text to input hides the function, so a later input(...) tries to call text and fails.

    An unfinished body needs a statement. Use an indented pass as a placeholder. A comment alone is not a body, and an unindented pass would sit outside the function instead.

  6. 6
    ExampleEnter a caller
    def line():
        print("----------")
    
    def banner():
        line()
        print("  REPORT")
        line()
    
    print("Start")
    banner()
    print("End")
    

    First both definitions run without printing. The top-level statement prints "Start", then banner() enters the banner body. Its first line calls line, so the banner must wait while that helper prints its dashes. Do not move ahead to the title until the helper finishes.

  7. 7
    ExplanationResume one level at a time

    When line finishes, execution resumes at the title print inside banner. The banner then calls line a second time, producing the second dashed line. When the banner finishes, the main program resumes and prints "End".

    Python's call stack records the unfinished calls and their return points. While the helper runs, the banner and the main program are waiting. A paper trace can mark these return points and record output as each print actually runs.

  8. 8
    ChallengeTrace another helper call

    What is the output order?

    def inner():
        print("I")
    
    def outer():
        print("O")
        inner()
        print("P")
    
    outer()
    print("Q")
    

    ---reveal---

    The lines are "O", "I", "P" and "Q". The outer body prints first, pauses for inner, then resumes at its next print. Only after outer ends does the final top-level statement run. Definition order alone does not determine output order.

  9. 9
    ChallengeMove a definition safely

    A file defines show with a body that calls border. It next defines border, then ends with a loop calling show() twice. Will the helper's lower definition cause an error, and how many times does border run?

    ---reveal---

    The program works: both definitions have run before the loop calls show. Each call enters show from its first body line and reaches one border call, so the helper runs twice. Moving the loop above the helper definition would make its name unavailable when first needed.

  10. 10
    RecapRead from the first active statement

    When tracing a function program:

    • Check the header and indentation to locate each body.
    • Start with top-level statements and enter a body only through a call.
    • Mark the caller's next statement before following a helper.
    • Record output when its print executes.

    If a call fails, read the traceback's final error, then inspect the failing body line and the caller that led there. The call path is often the key to understanding the error.

2

Fill the parameter slots

13 steps
Match values by position or name, then investigate defaults created at definition time.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionReuse a job with different values
  2. 2
    ExampleMatch the first and second inputs
  3. 3
    ExplanationEvaluate arguments before the body
  4. 4
    ChallengeCheck the argument count
  5. 5
    ExplanationUse names to show the roles
  6. 6
    ChallengeRepair a duplicated slot
  7. 7
    TipRead built-in keyword options
  8. 8
    ExampleLet the common choice be optional
  9. 9
    ChallengeSkip an optional choice by name
  10. 10
    Key InsightA default remembers its creation time
  11. 11
    ExampleSee why a list default keeps items
  12. 12
    ChallengeCombine defaults with named inputs
  13. 13
    RecapCheck the header against the call
3

Follow values back to the caller

14 steps
Separate output from results, then build branches, searches and nested calls that return the needed values.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionWatch what the caller receives
  2. 2
    ExampleReplace the call with its result
  3. 3
    ExplanationSeparate the screen from the result
  4. 4
    ChallengeFind the value used in addition
  5. 5
    TipCheck where the call is running
  6. 6
    ExampleStop at the first matching grade
  7. 7
    ChallengeCover the input between branches
  8. 8
    Key InsightLet a comparison answer the question
  9. 9
    ExampleReturn a found divisor
  10. 10
    ChallengeRepair an early success result
  11. 11
    ExampleUnpack a grouped result
  12. 12
    ExamplePass an inner result outward
  13. 13
    ChallengeCombine an early path and a result
  14. 14
    RecapTrace paths and returned values together
4

Track names and shared objects

11 steps
Separate local names from global names, then make a changing total explicit in the caller.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionAsk where the name belongs
  2. 2
    ExampleGive each call its own counter
  3. 3
    ExplanationKeep shadowed names separate
  4. 4
    ChallengeKeep the caller update explicit
  5. 5
    ExampleFollow a shared list through a parameter
  6. 6
    ExampleRead a global without a declaration
  7. 7
    Key InsightAssignment determines local scope early
  8. 8
    ChallengeChoose the scope of an update
  9. 9
    ConnectionMove the changing value through the call
  10. 10
    ChallengeSeparate mutation from reassignment
  11. 11
    RecapName the operation before predicting its effect
5

Design and check a score report

12 steps
Document a helper, plan its inputs and results, then check boundaries and caller data before connecting the program.

Save this lesson to follow every Walkthrough step by step.

  1. 1
    IntroductionBuild a program from clear jobs
  2. 2
    ExamplePut the description where help can find it
  3. 3
    ExplanationAdd details that affect a call
  4. 4
    ChallengeFind the missing documentation
  5. 5
    ExplanationChoose a job for each helper
  6. 6
    ExampleConnect the helpers in main
  7. 7
    ChallengeSeparate calculation from display
  8. 8
    TipKeep a working program as you build
  9. 9
    ExampleCheck a boundary that can expose a bug
  10. 10
    ChallengeFind where a wrong type enters
  11. 11
    ChallengeKeep documentation and a check in agreement
  12. 12
    RecapUse the interface to guide the checks

Python Functions practice questions

40 Practice Questions in 4 sets

Set 1: Trace inputs, scope and missing results10 Practice Questions

Question 1 of 10

How should this unfinished function body be completed so the file is valid but the function does nothing yet?

def print_ticket():
    # Work to be added later
  1. Add an unindented pass below the comment.
  2. Add another indented comment below it.
  3. Add an indented pass below the comment.
  4. Add an unindented print_ticket() below it.
Show answerHide answer
Answer: C
An indented pass is a valid body statement that does nothing. Comments alone do not count as the required body, so adding another comment still leaves the definition incomplete. An unindented statement belongs outside the function and cannot supply its missing body.

Question 2 of 10

What does this program print?

def show_scaled(value, factor):
    print(value * factor)

entry = "6"
show_scaled(entry, 3)
  1. "666"
  2. "18"
  3. "6 6 6"
  4. "9"
Show answerHide answer
Answer: A
The argument entry contains text, and Python repeats that text when it is multiplied by the integer 3. The output is "666", with no inserted spaces. Getting 18 would require converting the text to a number before the multiplication; the parameter name does not perform that conversion.

Question 3 of 10

What value is returned?

step = 4

def advance(position, amount=step):
    return position + amount

step = 9
result = advance(10)
  1. 19
  2. 9
  3. 10
  4. 14
Show answerHide answer
Answer: D
The default expression is evaluated when def runs, while step is 4. Omitting amount therefore adds 4 to 10 and returns 14. Changing step to 9 later does not update the stored default; 19 would require explicitly passing the new value.

Question 4 of 10

What single change makes result hold 16 without displaying it inside the helper?

def square(n):
    print(n * n)

result = square(4)
  1. Replace the body with return print(n * n).
  2. Replace the body with return n * n.
  3. Add return after the existing print.
  4. Replace the call with result = print(square(4)).
Show answerHide answer
Answer: B
Returning n * n sends 16 directly to the assignment without printing inside the helper. return print(n * n) still prints and returns the result of print, which is None. A bare return after a print also gives None, so it does not supply the computed number.

Question 5 of 10

What is printed?

def pack(total, size):
    return total // size, total % size

def double(n):
    return n * 2

boxes, spare = pack(29, 6)
print(double(boxes) + spare)
  1. "12"
  2. "9"
  3. "14"
  4. "13"
Show answerHide answer
Answer: D
Packing 29 into groups of 6 returns the tuple (4, 5), so boxes becomes 4 and spare becomes 5. Doubling the box count gives 8, then adding 5 prints "13". Getting 14 swaps the two unpacked values before doubling, which does not follow the return order.

Question 6 of 10

What is printed after both calls?

def add_guest(guests):
    guests.append("Sol")

def replace_guests(guests):
    guests = ["Tao"]

party = ["Ren"]
add_guest(party)
replace_guests(party)
print(party)
  1. ['Tao']
  2. ['Ren']
  3. ['Ren', 'Sol']
  4. ['Ren', 'Sol', 'Tao']
Show answerHide answer
Answer: C
add_guest appends to the same list that party refers to, adding "Sol". replace_guests only reassigns its local parameter to a new list, so party still refers to ['Ren', 'Sol']. Expecting ['Tao'] confuses redirecting the local name with replacing the caller's reference.

Question 7 of 10

What happens when inspect() is called?

count = 11

def inspect():
    print(count)
    count = 2

inspect()
  1. It raises UnboundLocalError before printing a value.
  2. It prints "11" and then changes global count to 2.
  3. It prints "11" and then creates local count as 2.
  4. It prints "2" because the local assignment runs first.
Show answerHide answer
Answer: A
Assignment to count makes it local throughout the body, including the earlier print. That local has no value when the print tries to read it, so the call raises UnboundLocalError. Python does not first use the global 11 and switch to local scope only after reaching the assignment.

Question 8 of 10

What does show.__doc__ contain?

def show():
    value = 2
    """Display the current value."""
    print(value)
  1. The sentence "Display the current value."
  2. None
  3. The number 2
  4. The source line print(value)
Show answerHide answer
Answer: B
The string follows an assignment, so it is not the first statement and does not become the function's docstring. With no recognized docstring, show.__doc__ is None. Triple quotes alone are insufficient; move the description above the assignment to store it as documentation.

Question 9 of 10

Three parts of a program print a title between identical separator lines. What change removes repeated logic while keeping different titles?
  1. Make a separate no-parameter function for each title.
  2. Store every title in a global read by one printer.
  3. Put all three blocks unchanged inside main.
  4. Write print_heading(title) and pass each title.
Show answerHide answer
Answer: D
One function can hold the shared separator-and-title structure, while a parameter supplies each different title. A later separator change then needs one body edit. Moving the three unchanged blocks into main only relocates the repetition and still requires several edits to change that shared behavior.

Question 10 of 10

A category should be "full" at 50 or above and "partial" below 50. What pair of test inputs best exposes an accidental > 50 test?
  1. 50 and 49
  2. 51 and 52
  3. 25 and 30
  4. 49 and 48
Show answerHide answer
Answer: A
The input 50 must take the "full" path, while 49 must take the "partial" path. Testing them checks the exact boundary and the neighboring lower case, exposing a strict comparison that rejects 50. Inputs 51 and 52 both pass either comparison, so they miss the boundary error.
Set 2: Read calls and follow their results10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

What does the final line print?

def triple(value):
    print(value * 3)

answer = triple(4)
print(answer)
  1. "None"
  2. "12"
  3. "4"
  4. Nothing; the last line is skipped.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

What does this function return for first_factor(25)?

def first_factor(n):
    for candidate in range(2, n):
        if n % candidate == 0:
            return candidate
        return n
  1. 5 after checking candidates 2 through 5.
  2. None because the first candidate fails.
  3. 25 after checking every candidate.
  4. 25 after checking only candidate 2.
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

What are the two output lines?

level = 7

def show_level():
    level = 3
    print(level)

show_level()
print(level)
  1. "3", then "3"
  2. "7", then "3"
  3. "3", then "7"
  4. "7", then "7"
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

What output does this program produce?

def announce():
    print("Open")

print("Ready")
  1. "Open" and then "Ready".
  2. Only "Ready" on one line.
  3. "Ready", then "Open" below.
  4. No output at all is shown.
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

What is the output order?

def mark():
    print("M")

def stage():
    print("S")
    mark()
    print("T")

print("R")
stage()
  1. "M", "S", "T", "R"
  2. "R", "M", "S", "T"
  3. "R", "S", "T", "M"
  4. "R", "S", "M", "T"
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

What does this call print?

def describe_trip(origin, destination):
    print(origin, "to", destination)

describe_trip("Mesa", "Salem")
  1. "Mesa to Salem"
  2. "Salem to Mesa"
  3. "origin to destination"
  4. "Mesa Salem to"
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

How can you call this function using "Inez" for the person and "West" for the room?

def show_booking(person, room):
    print(person, room)
  1. show_booking(person="Inez", "West")
  2. show_booking("Inez", person="West")
  3. show_booking(room="West", person="Inez")
  4. show_booking(name="Inez", room="West")
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

What is displayed?

def label(text, copies=2):
    print(text * copies)

label("Go")
  1. "Go"
  2. "GoGo"
  3. "Go2"
  4. "Go Go"
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

What is the role of the first string in this function?

def square(n):
    """Return the square of n."""
    return n * n
  1. A stored description shown by help(square).
  2. The text returned by every call to square.
  3. A message printed before the multiplication.
  4. A default value used when n is omitted.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A program reads a distance, converts it and displays a message. What interface lets the conversion be checked without typing input?
  1. A converter with no parameters that reads the distance.
  2. A converter taking distance and returning the converted value.
  3. A converter taking distance and printing the converted value.
  4. A converter with no parameters that changes a global distance.
Show answerHide answer

Save this lesson to see this answer.

Set 3: Diagnose calls and repair program behavior10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

Why does this program succeed even though tick is defined below report?

def report():
    tick()

def tick():
    print("Done")

report()
  1. Python runs every function body once before any calls.
  2. The report definition moves tick above itself.
  3. The report body is copied into the tick definition.
  4. Both definitions execute before report() calls tick.
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

What argument value reaches width?

def show_width(width):
    print(width)

base = 8
show_width(base + 3)
  1. 8
  2. 11
  3. The text "base + 3"
  4. No value because the names differ.
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

Why does this call fail?

def mark_pages(first, last):
    print(first, last)

mark_pages(4, first=9)
  1. The keyword follows a positional argument.
  2. Two integer arguments cannot be used together.
  3. first receives two values and last receives none.
  4. Keyword names must match caller variable names.
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

What are the two printed lists?

def collect(value, bucket=[]):
    bucket.append(value)
    return bucket

print(collect("red"))
print(collect("blue", []))
  1. ['red'], then ['blue']
  2. ['red'], then ['red', 'blue']
  3. ['red', 'blue'], then ['blue']
  4. ['blue'], then ['red', 'blue']
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

What is the complete output?

def shift(n):
    return n + 2
    print("shifted")

shift(5)
print("done")
  1. "shifted", then "done"
  2. "7", then "done"
  3. Only "done"
  4. Only "shifted"
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

A function must return True exactly when an integer is prime. Why does this body wrongly accept 35?

def is_prime(n):
    if n < 2:
        return False
    for d in range(2, n):
        if n % d == 0:
            return False
        else:
            return True
  1. It tries all candidates but skips 5.
  2. It returns False at candidate 5.
  3. It treats every odd number below 2 as prime.
  4. It returns True at candidate 2 before trying 5.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

What is printed?

total = 2

def add(amount):
    global total
    total = total + amount
    return total

first = add(4)
second = add(first)
print(total, second)
  1. "6 12"
  2. "12 12"
  3. "8 8"
  4. "6 6"
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A function changes its default duration from 15 minutes to 20 minutes, with the same calculation and units. What documentation change is needed?
  1. Update the optional parameter's documented default to 20 minutes.
  2. Rename the function in the docstring to mention 20 minutes.
  3. Move the docstring after the calculation to document its new result.
  4. Remove the parameter description because the header shows its name.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

A numeric helper keeps the same name, parameters, returned values and documented effects after its body is simplified. Why can existing callers remain unchanged?
  1. Callers receive all local variables from the new body.
  2. Python stores the old body until all callers are rewritten.
  3. Callers rely on an interface whose behavior is preserved.
  4. A docstring makes Python automatically repair each call.
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

A numeric helper fails at if score >= 60: after the caller passes input("Score: "). What repair addresses the input type?
  1. Change the comparison to score >= "60".
  2. Convert the input with float() before calling the helper.
  3. Add a print after the comparison to display score.
  4. Remove the parameter and read a global score instead.
Show answerHide answer

Save this lesson to see this answer.

Set 4: Combine function rules in new situations10 Practice Questions

Save this lesson to see every answer and practice every set.

Question 1 of 10

How can the caller update stock explicitly without the helper changing a global?

stock = 18

def remove(stock, amount):
    return stock - amount

# caller statement
  1. remove(stock, 4)
  2. stock = remove(4, stock)
  3. stock = remove(stock, 4)
  4. remove(stock=4, amount=stock)
Show answerHide answer

Save this lesson to see this answer.

Question 2 of 10

How should a function that displays a payment receipt be named in the usual Python style?
  1. print_receipt
  2. print-receipt
  3. 2print_receipt
  4. print receipt
Show answerHide answer

Save this lesson to see this answer.

Question 3 of 10

What is printed?

def outer():
    inner()
    print("Y")

outer()

def inner():
    print("X")
  1. "X", then "Y"
  2. Only "Y", followed by a NameError
  3. No output; NameError occurs inside outer.
  4. Only "X", followed by a NameError
Show answerHide answer

Save this lesson to see this answer.

Question 4 of 10

What is the complete output, including line breaks?

print("N", "S", sep="/", end="|")
print("E", "W", sep="-")
  1. Two lines: "N/S|" then "E-W"
  2. One line: "N/S|E-W"
  3. One line: "N S|E W"
  4. Two lines: "N/S" then "|E-W"
Show answerHide answer

Save this lesson to see this answer.

Question 5 of 10

A new call that omits items should start a fresh list, but a supplied list should be extended in place. What replacement body is correct?

def add_code(code, items=None):
    # replacement body
  1.     items = []
        items.append(code)
        return items
    
  2.     if items == []:
            items = []
        items.append(code)
        return items
    
  3.     if items is None:
            return []
        items.append(code)
        return items
    
  4.     if items is None:
            items = []
        items.append(code)
        return items
    
Show answerHide answer

Save this lesson to see this answer.

Question 6 of 10

What change lets this function return the first matching candidate, or None only after all candidates fail?

def find_divisor(n):
    for d in range(3, n):
        if n % d == 0:
            return d
        else:
            return None
  1. Change return None to return False in the else.
  2. Remove the else and put return None after the loop.
  3. Put both return statements after the loop.
  4. Move return d before the if test inside the loop.
Show answerHide answer

Save this lesson to see this answer.

Question 7 of 10

What does the final line print?

def change(values):
    values.append("B")
    values = ["C"]
    values.append("D")
    return values

original = ["A"]
result = change(original)
print(original, result)
  1. ['A'] ['C', 'D']
  2. ['A', 'B', 'D'] ['C']
  3. ['C', 'D'] ['C', 'D']
  4. ['A', 'B'] ['C', 'D']
Show answerHide answer

Save this lesson to see this answer.

Question 8 of 10

A placeholder helper contains only a docstring and pass. Its caller adds the helper's result to 7 and gets TypeError. What should be implemented next?
  1. Return the numeric result the helper's job promises.
  2. Print the promised number before the pass statement.
  3. Move the docstring below pass to make it executable.
  4. Repeat the helper call before adding its result to 7.
Show answerHide answer

Save this lesson to see this answer.

Question 9 of 10

What is printed?

def add_fee(amount):
    return amount + 3

def twice(amount):
    return amount * 2

print(twice(add_fee(5)))
  1. "13"
  2. "8"
  3. "10"
  4. "16"
Show answerHide answer

Save this lesson to see this answer.

Question 10 of 10

What is printed?

rate = 2

def scale(value, factor=rate):
    return value * factor

def reset():
    global rate
    rate = 5

reset()
print(scale(3), scale(3, rate))
  1. "15 15"
  2. "6 6"
  3. "6 15"
  4. "15 6"
Show answerHide answer

Save this lesson to see this answer.

Stuck on your own question? Homework Help

Key Terms

56 Key Terms, each with its definition

A

Argument
An argument is a value supplied in a function call, after any expression producing that value has been evaluated.
In area(side + 1, 2), Python calculates the first argument before starting the area body.

B

Boolean function
A Boolean function answers a yes-or-no question by returning True or False, often directly from a comparison.
The body return n % 2 == 0 lets is_even(n) be used directly as an if condition.
Boundary test
A boundary test checks an input exactly at a decision limit, often alongside a nearby value taking the other path.
Scores of 90 and 89.9 expose a grade condition that accidentally uses > instead of >=.

C

Call stack
The call stack is Python's record of calls that have started but not finished, including where their callers resume.
While a line helper runs inside a banner call, both unfinished calls have places in the call stack.
Caller
A caller is the code that invokes a function and waits for it to finish before continuing after the call.
When banner() calls line(), the banner body is the caller of the line-drawing function.
Constant
A constant is a setting intended to stay fixed; Python convention writes file-level constant names in uppercase.
A function can read TAX_RATE = 0.25 to calculate tax without declaring that name global.

D

Debug print
A debug print is a temporary display of a value while investigating a bug, removed when the investigation is complete.
A first-line print can reveal the unexpected score reaching a helper from its calling code.
Decomposition
Decomposition splits a problem into smaller jobs that can each be implemented, understood and checked as a function.
A score-report program separates reading scores, calculating an average and choosing a grade.
Default value
A default value is a value stored for a parameter when the definition runs and used when a call omits that argument.
In def greet(name, greeting="Hello"):, a call can omit the greeting and still supply the name.
Docstring
A docstring is the first-statement string in a function body, stored with the function to describe its use to callers.
A converter's docstring can explain its input and output temperature units before anyone reads the formula.

E

Early return
An early return ends a function before its later statements run, often when a branch or search has already found the answer.
A divisor search returns 7 for 91 as soon as that candidate divides it evenly, ending the loop too.
end
The end parameter of print controls the text appended after its displayed values, using a newline by default.
Using end="..." lets the next print continue after the dots instead of starting a new line.
Expected result
An expected result is an answer worked out independently before a check, used to judge what a function actually returns.
Calculating an average by hand lets you spot a program output that looks plausible but is wrong.

F

Flow of execution
The flow of execution is the order in which statements run, including jumps into functions and returns to their callers.
A report can print "Start", enter banner(), finish its helper calls, and then print "End".
Fruitful function
A fruitful function returns a useful result that the calling code can use in an expression, assignment or condition.
A temperature converter returning a number can feed a printed table or a comparison with a limit.
Function
A function is a named block of code that performs a job when called, letting a program reuse the same logic.
A receipt program can call print_receipt() whenever it needs to display another receipt.
Function body
A function body is the indented block of statements below its header, followed from the start on each call.
Two indented print lines below def greet(): both belong to the function's body.
Function call
A function call is an expression that runs a function, written with its name and parentheses containing any arguments.
The line greet() runs the greeting, while a line containing only greet does not.
Function definition
A function definition is a def statement with a header and indented body that creates a function under a name.
Python creates greet at def greet(): and waits for a call before running its body.

G

global statement
The global statement makes a name inside a function refer to the file-level binding for subsequent reads and assignments.
Place global total before the function uses total to update a shared running count.
Global variable
A global variable belongs to a file's global scope and can be read by functions in that file under the name-lookup rules.
A top-level x = 10 remains 10 when a helper assigns its own separate local x = 5.

H

Header
A function header is the opening line containing def, the function name, parameter parentheses and a colon.
In def print_line(length):, the header names the job and its input before the body begins.
help
The help function displays information about a function, including its signature and stored docstring when present.
Use help(to_fahrenheit) to inspect the converter without first supplying a temperature to it.
Hidden state
Hidden state is information a function depends on or changes without showing it through its parameters and returned result.
A function that updates a global total needs that total prepared before an independent check.

I

Incremental development
Incremental development builds a program through small additions, checking each piece before connecting more work.
Checking an average helper first narrows the code to inspect when a later grade report goes wrong.
Interface
A function interface is its name, parameters, returned result and documented behavior: the agreement used by its callers.
A calculation can be rewritten while calls stay unchanged if the interface still gives the same promised result.

K

Keyword argument
A keyword argument names its destination parameter in a call, so matching depends on the name instead of position.
The call describe_pet(name="Milo", animal="cat") fills the parameters in a readable order.

L

Local variable
A local variable belongs to a function call, including its parameters and ordinary names assigned in that function.
Each call can initialize its own count = 0, so two calls can independently print the value 1.

M

main
A main function coordinates the smaller jobs of a program, connecting inputs, helper results and the final display.
A final main() call runs a score report's steps after all the helper definitions have executed.
Mixed argument passing
Mixed argument passing supplies some values positionally and others by keyword, with positional values first.
In describe_pet("cat", name="Milo"), the first slot is filled by position and the second by name.
Multi-line docstring
A multi-line docstring has a summary, a blank line and further details about inputs, defaults, results and effects.
A bill-sharing function can document that tip_rate=0.2 is a fraction of the bill, not 20.
Mutable default
A mutable default is a stored default object whose contents can change, so omitted-argument calls can share earlier changes.
Appending an item to a default basket list can leave that item visible during the next call.
Mutation
Mutation changes an existing object's contents, so another name referring to the same object can observe that change.
Appending "Ben" through a list parameter changes the guest list that the caller passed in.

N

Nested call
A nested call is a function call inside another call's argument expression, whose result is needed before the outer call runs.
In print(to_fahrenheit(add(10, 15))), addition runs before conversion, then printing.
None
None is Python's special value for no value, also useful as a signal that an optional input has been omitted.
With basket=None, the function can create a fresh list inside if basket is None:.

O

One-line docstring
A one-line docstring is a short command sentence, conventionally inside triple double quotes and ending with a period.
"Return the area of a rectangle." describes the job without repeating the function's signature.
Optional parameter
An optional parameter has a default, allowing a call to leave it out or replace that default with an explicit argument.
A coffee function call can set milk="oat" while leaving an earlier optional shot-count parameter at its default.

P

Parameter
A parameter is a name in a function header that receives an argument value as a local variable for a call.
The header def area(width, height): gives each area call local names for its two dimensions.
pass
The pass statement is a placeholder that performs no action, allowing a planned function body to be valid Python.
A function containing only pass can be called while its real printing behavior is still being written.
Positional argument
A positional argument is matched to a parameter by its order in a call, with the first value filling the first slot.
For describe_pet(animal, name), describe_pet("cat", "Milo") puts "cat" into animal.
Procedural abstraction
Procedural abstraction lets code use a function through its agreed job without depending on how its body performs that job.
A caller can use letter_grade(avg) without following every threshold comparison in the body.

R

Reassignment
Reassignment gives an existing name a new value or object; reassigning a parameter changes that local binding.
The line points = points + 10 changes the local parameter, leaving the caller's score unchanged.
Required parameter
A required parameter has no default and must receive a value in every valid call, by position or an accepted keyword.
With def greet(name, greeting="Hello"):, omitting name causes a missing-argument error.
Return path
A return path is a route through a function's branches and loops that reaches a return statement or the body's end.
A sign function needs a result for zero as well as routes returning positive and negative labels.
Return statement
A return statement ends the current function call and sends its result to the caller; without an expression it sends None.
The statement return width * height lets the caller save an area or use it in another calculation.
Return value
A return value is the result a call supplies to its caller, where it can be stored, tested or passed to another operation.
After area = rectangle_area(4, 2.5), area holds the returned result 10.0 for later use.

S

Scope
Scope is the part of a program in which a name can be used, determining which variable a reference identifies.
A name created only inside make_greeting() is unavailable to a top-level print after the call.
sep
The sep parameter of print controls the text inserted between displayed values, using a space by default.
The call print("a", "b", "c", sep="-") displays the three letters as "a-b-c".
Shadowing
Shadowing occurs when a local name hides a same-spelled global inside a function without replacing the global binding.
If a helper assigns local x = 5 while global x = 10, the helper's x produces 5 and a later global x still produces 10.
Stub
A stub is an unfinished function with its intended header and a placeholder body, allowing callers to run during development.
A docstring and pass create a valid stub, though its calls still return None until implemented.

T

Traceback
A traceback is an error report showing the unfinished call path, the failing line and the final error type and message.
In a traceback, read the final error first, then inspect the failing helper line and the caller that supplied its inputs.
Tuple
A tuple is a grouped sequence of values; comma-separated values in a return form one tuple result for the caller.
The statement return total // people, total % people groups a share and a remainder together.
TypeError
A TypeError reports an unsuitable operation on a value or a call with an invalid argument combination.
Calling a two-parameter function with one argument raises TypeError for the missing input.

U

UnboundLocalError
An UnboundLocalError occurs when a function tries to read a local name before that local name has a value.
A later assignment to count makes an earlier print(count) local too, even if a global exists.
Unpacking
Unpacking assigns the separate values of a grouped result to matching names, keeping the values in their original order.
If share(17, 5) returns 17 // 5, 17 % 5, the assignment each, left = share(17, 5) puts 3 in each and 2 in left.

V

Void function
A void function is a function used for an effect, such as printing, that supplies no useful result beyond None.
A greeting printer can display "Hello!" successfully even though its caller receives None.

About this lesson

By StudeliReport a mistake

Make your own Study Materials

Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.

Get Started