πŸŽ“ Velnov

🐍 Python · Topic 10 of 20

Functions β€” Python Questions with Answers

Start with the study notes on Functions (definitions, examples and a quick revision), then work through 30 practice questions, each with the correct answer and a clear explanation of why it is right. When you are ready, take this topic as an interactive quiz to test yourself.

8 easy Β· 14 medium Β· 8 hard Β· Part of Python: Master Python from basics to advanced - 20 topics.

Topic overview

Functions – reusable blocks of code

1. Defining and calling a function

A function is a named block of code that runs when you call it. You define it with def; its body runs only when it is called.

def greet(name):
    print(f"Hello, {name}!")

greet("Ana")
greet("Ben")
OutputHello, Ana!
Hello, Ben!

Remember: In def greet(name), name is a parameter. In greet("Ana"), "Ana" is an argument.

2. return vs print

return sends a value back to the caller, so the result can be stored and reused. A function with no return gives back None.

def add(a, b):
    return a + b

total = add(2, 3) * 10
print(total)

def show(a, b):
    print(a + b)

result = show(2, 3)
print(result)
Output50
5
None

Remember: return exits the function immediately; code after it in the same branch never runs.

3. Default and keyword arguments

def book(seat, meal="veg"):
    print(seat, meal)

book("12A")
book("12A", "non-veg")
book(meal="none", seat="3C")
Output12A veg
12A non-veg
3C none

4. *args and **kwargs

def total(*args):
    return sum(args)

print(total(1, 2, 3), total(5))

def config(**kwargs):
    for key, value in kwargs.items():
        print(key, "=", value)

config(theme="dark", size=12)
Output6 5
theme = dark
size = 12

5. Returning several values

Returning several values really returns one tuple, which you can unpack.

def stats(nums):
    return min(nums), max(nums)

lo, hi = stats([3, 8, 1])
print(lo, hi)
Output1 8

6. Scope: local and global

Variables created inside a function are local: they exist only while the function runs. Functions can read global variables, but assigning to one needs the global keyword. Usually it is better to pass values in and return them.

x = 5
def show():
    print(x)        # reading a global is fine
show()

count = 0
def inc():
    global count
    count += 1
inc()
print(count)
Output5
1

Remember: Assigning to a name anywhere in a function makes it local for the whole function. Reading it before the assignment gives UnboundLocalError.

7. The mutable default trap

A default value is created once, when the function is defined. A default list is therefore shared between calls. Use None and create the list inside.

def add_bad(item, lst=[]):
    lst.append(item)
    return lst
print(add_bad(1), add_bad(2))

def add_good(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst
print(add_good(1), add_good(2))
Output[1, 2] [1, 2]
[1] [2]

8. Lambda functions and sort keys

A lambda is a small nameless function with a single expression. It is most often used as a key for sorting.

double = lambda x: x * 2
print(double(5))
words = ["banana", "fig", "apple"]
print(sorted(words, key=len))
students = [("Ana", 92), ("Ben", 85)]
print(sorted(students, key=lambda s: s[1]))
Output10
['fig', 'apple', 'banana']
[('Ben', 85), ('Ana', 92)]

9. Recursion

A recursive function calls itself on a smaller problem, and must have a base case that stops it. Without one, Python raises RecursionError (the default limit is about 1,000 calls).

def factorial(n):
    if n <= 1:          # base case
        return 1
    return n * factorial(n - 1)

print(factorial(5))
Output120

10. Functions are objects

Functions can be stored in variables, kept in lists, passed to other functions and returned. This is called being first-class.

def shout(text):
    return text.upper()

def apply(func, value):
    return func(value)

f = shout                     # no brackets: the function itself
print(f("hi"))
print(apply(len, "hello"))
OutputHI
5

Example: Type hints such as def add(a: int, b: int) -> int: document the expected types, but Python does not enforce them.

11. Common misconceptions

MisconceptionCorrect understanding
print and return do the same job.print only shows a value; return gives it back for further use.
A default list starts fresh on every call.It is created once and shared; use None as the default.
Variables made inside a function exist outside it.They are local and disappear when the function ends.
def f(a=1, b): is fine.Parameters with defaults must come after required ones.
Type hints stop wrong types at runtime.Python ignores them at runtime; tools like mypy check them.

12. Quick revision

def
Defines a function.
Parameter / argument
The placeholder / the actual value passed.
return
Sends a value back and exits the function.
Default argument
Used when the caller leaves it out.
*args
Extra positional arguments, as a tuple.
**kwargs
Extra keyword arguments, as a dict.
lambda
A small one-expression function.
Recursion
A function calling itself, with a base case.

13. Test your understanding

  1. What does a function without return give back?

    Show answer

    None

  2. In def greet(name), what is name called?

    Show answer

    A parameter.

  3. What does *args collect?

    Show answer

    Extra positional arguments, as a tuple.

  4. What does **kwargs collect?

    Show answer

    Extra keyword arguments, as a dict.

  5. What is wrong with def add(item, lst=[]):?

    Show answer

    The default list is shared between calls.

  6. How do you sort words by length?

    Show answer

    sorted(words, key=len)

  7. What must every recursive function have?

    Show answer

    A base case.

  8. How do you return two values?

    Show answer

    return a, b (it returns a tuple).

Key takeaway: Functions package code behind a name: take inputs as parameters, give results back with return, and beware the shared mutable default.

Notes written by Velnov. Every code example with an output was run in Python 3 to check that the output shown is exactly what Python prints.

Key concepts in this topic

defFunction callsCallingNonereturnprint()ParametersArgumentsDefault argumentsKeyword argumentsReadabilityArgument orderSyntaxError*args**kwargsDictionariesTuplesUnpackinglambdaAnonymous functionssorted()key functionsLocal scopeNameError

Jump to: Easy Β· Medium Β· Hard

Easy questions (8)

Q1. easy

Which is the correct way to define a function called greet?

def greet():
    print("Hello!")

greet()   # call it - Hello!
  1. A def greet():
  2. B function greet():
  3. C define greet():
  4. D greet() =

Answer: A β€” def greet():

Functions are defined with the def keyword, the name, parentheses for parameters, and a colon. The body is indented below.

defFunction calls

Q2. easy

What happens if you define a function but never CALL it?

def greet():
    print("Hi")   # not printed yet!

greet()            # NOW it prints
  1. A Its body runs once automatically
  2. B Nothing - the body only runs when the function is called
  3. C SyntaxError
  4. D It runs at the end of the program

Answer: B β€” Nothing - the body only runs when the function is called

def only CREATES the function. The body executes each time you call it with parentheses: greet(). Defining without calling produces no output.

defCalling

Q3. easy

What does a function return if it has no return statement?

def greet(name):
    print(f"Hello {name}")

result = greet("Ana")   # prints Hello Ana
print(result)            # None
  1. A 0
  2. B Empty string
  3. C None
  4. D Error

Answer: C β€” None

Every function returns something. Reaching the end without return (or a bare return) gives None.

  • print displays; return hands a value back - the classic beginner confusion.

Nonereturn

Q4. easy

What is the difference between print() and return in a function?

def add(a, b):
    return a + b

total = add(2, 3) * 10   # 50 - reusable!
  1. A None - they do the same
  2. B print shows a value on screen; return sends the value back to the caller for further use
  3. C return shows on screen; print sends back
  4. D return only works with numbers

Answer: B β€” print shows a value on screen; return sends the value back to the caller for further use

print() is for humans (display only); return is for code - the caller receives the value and can store, compare or reuse it. A function that only prints can't have its result used in calculations.

returnprint()

Q5. easy

In def greet(name): ... and the call greet("Ana") - what are name and "Ana" called?

  1. A name is the parameter; "Ana" is the argument
  2. B name is the argument; "Ana" is the parameter
  3. C Both are parameters
  4. D Both are arguments

Answer: A β€” name is the parameter; "Ana" is the argument

PARAMETER = the placeholder in the definition (name). ARGUMENT = the actual value passed when calling ("Ana"). Parameter is the parking spot, argument is the car.

ParametersArguments

Q18. easy

What does return do the moment it executes?

def check(n):
    if n < 0:
        return "negative"   # exits here for negatives
    return "positive"
    print("never runs")
  1. A Pauses the function
  2. B Immediately EXITS the function, handing back the value - remaining lines don't run
  3. C Prints the value
  4. D Restarts the function

Answer: B β€” Immediately EXITS the function, handing back the value - remaining lines don't run

return ends the function on the spot. Code after an executed return is unreachable. Multiple returns are fine - typically one per branch.

returnEarly return

Q25. easy

By PEP 8 convention, function names should be written as:

  1. A snake_case: calculate_total()
  2. B CamelCase: CalculateTotal()
  3. C ALLCAPS: CALCULATETOTAL()
  4. D kebab-case: calculate-total()

Answer: A β€” snake_case: calculate_total()

Functions and variables use snake_case; CamelCase is reserved for class names; ALL_CAPS for constants. (kebab-case is illegal - hyphens mean subtraction.)

PEP 8Naming conventions

Q30. easy

Why split a program into functions at all?

  1. A Reuse, readability, easier testing, and no copy-pasted code
  2. B Functions make programs run faster automatically
  3. C Python requires at least 5 functions
  4. D Only to use return

Answer: A β€” Reuse, readability, easier testing, and no copy-pasted code

Functions package logic behind a name: write once, call anywhere, test in isolation, and read programs as a story of well-named steps. The DRY principle: Don't Repeat Yourself.

DRY principleCode organization

Medium questions (14)

Q6. medium

What is the output? def greet(name="Guest"): print("Hello", name) greet()

def greet(name="Guest"):
    print("Hello", name)

greet()         # Hello Guest
greet("Ana")   # Hello Ana
  1. A Hello
  2. B Hello Guest
  3. C Error - missing argument
  4. D Hello name

Answer: B β€” Hello Guest

name="Guest" is a DEFAULT argument - used when the caller doesn't supply one. greet() -> 'Hello Guest'; greet("Ana") -> 'Hello Ana'.

Default arguments

Q7. medium

What are keyword arguments in: book_ticket(seat="12A", meal="veg")?

def book(seat, meal):
    print(seat, meal)

book(meal="veg", seat="12A")   # order-free
  1. A Arguments passed by NAME, so order doesn't matter
  2. B Arguments that must be strings
  3. C Reserved Python keywords
  4. D Arguments that can't have defaults

Answer: A β€” Arguments passed by NAME, so order doesn't matter

Passing name=value lets you give arguments in ANY order and makes calls self-documenting. book_ticket(meal="veg", seat="12A") works identically.

Keyword argumentsReadability

Q9. medium

What is *args used for in a function definition?

def total(*args):
    return sum(args)

print(total(1, 2, 3))   # 6
print(total(5))          # 5
  1. A To accept any number of positional arguments as a tuple
  2. B To multiply arguments
  3. C To pass arguments by reference
  4. D To accept keyword arguments as a dict

Answer: A β€” To accept any number of positional arguments as a tuple

*args collects extra positional arguments into a tuple, so the function accepts any count: total(1), total(1,2,3)... **kwargs does the same for keyword arguments (into a dict).

*args**kwargs

Q10. medium

What does **kwargs collect in def config(**kwargs)?

def config(**kwargs):
    for key, value in kwargs.items():
        print(key, "=", value)

config(theme="dark", size=12)
  1. A Extra POSITIONAL arguments as a list
  2. B Extra KEYWORD arguments as a dictionary
  3. C Only two arguments
  4. D Global variables

Answer: B β€” Extra KEYWORD arguments as a dictionary

**kwargs gathers surplus name=value arguments into a dict: config(theme="dark", size=12) gives kwargs = {'theme': 'dark', 'size': 12}.

**kwargsDictionaries

Q11. medium

What is the output? def stats(nums): return min(nums), max(nums) lo, hi = stats([3, 8, 1]) print(lo, hi)

def stats(nums):
    return min(nums), max(nums)   # a tuple

lo, hi = stats([3, 8, 1])
print(lo, hi)   # 1 8
  1. A 1 8
  2. B 3 8
  3. C (1, 8)
  4. D Error - can't return two values

Answer: A β€” 1 8

Returning two values actually returns ONE tuple (1, 8), which unpacks into lo and hi. This is how Python 'returns multiple values'.

TuplesUnpacking

Q12. medium

What is a lambda function?

double = lambda x: x * 2
print(double(5))   # 10

# same as:
def double(x):
    return x * 2
  1. A A small anonymous one-expression function
  2. B A function that runs in parallel
  3. C A Greek module
  4. D A function with no arguments

Answer: A β€” A small anonymous one-expression function

lambda arguments: expression creates a tiny unnamed function in one line. Best used inline where a short function is needed once - e.g. as a sort key.

lambdaAnonymous functions

Q14. medium

What happens? def f(): x = 10 f() print(x)

def f():
    x = 10
    return x

x = f()      # bring it out via return
print(x)      # 10
  1. A Prints 10
  2. B NameError - x is local to f and doesn't exist outside
  3. C Prints None
  4. D Prints 0

Answer: B β€” NameError - x is local to f and doesn't exist outside

Variables created inside a function are LOCAL - they exist only while the function runs and vanish afterwards. To get the value out, return it.

Local scopeNameError

Q15. medium

What is the output? x = 5 def show(): print(x) show()

x = 5
def show():
    print(x)   # reading global - fine
show()          # 5
  1. A 5 - functions can READ global variables
  2. B NameError
  3. C None
  4. D 0

Answer: A β€” 5 - functions can READ global variables

Functions can freely READ globals (Python looks outward: Local -> Enclosing -> Global -> Built-in, the LEGB rule). Only ASSIGNING to them requires the global keyword.

LEGB ruleglobal

Q19. medium

def f(a, b): ... What happens when you call f(1)?

def f(a, b):
    return a + b
# f(1)         # TypeError
f(1, 2)        # 3
  1. A b becomes None
  2. B b becomes 0
  3. C TypeError: f() missing 1 required positional argument: 'b'
  4. D Runs with a=1 only

Answer: C β€” TypeError: f() missing 1 required positional argument: 'b'

Parameters without defaults are REQUIRED. Calling with too few (or too many) arguments raises TypeError with a helpful message naming the missing parameter.

TypeErrorRequired arguments

Q21. medium

What is recursion?

def factorial(n):
    if n == 0:          # base case
        return 1
    return n * factorial(n - 1)

print(factorial(5))   # 120
  1. A A function that calls ITSELF, with a base case to stop
  2. B A loop inside a function
  3. C Calling two functions at once
  4. D A function without a return

Answer: A β€” A function that calls ITSELF, with a base case to stop

A recursive function solves a problem by calling itself on a smaller piece, stopping at a base case. Classic example: factorial(n) = n * factorial(n-1), stopping at factorial(0) = 1.

RecursionBase case

Q23. medium

What is the output of factorial(3) using: def factorial(n): if n <= 1: return 1 return n * factorial(n - 1)

  1. A 3
  2. B 6
  3. C 9
  4. D 1

Answer: B β€” 6

Trace it: factorial(3) = 3 * factorial(2) = 3 * 2 * factorial(1) = 3 * 2 * 1 = 6.

RecursionTracing

Q24. medium

What are the type hints in: def add(a: int, b: int) -> int:

def add(a: int, b: int) -> int:
    return a + b

add("x", "y")   # runs! returns 'xy' - hints not enforced
  1. A Optional annotations documenting expected types - not enforced at runtime
  2. B Strict type checks that raise errors on wrong types
  3. C Comments
  4. D Required in Python 3

Answer: A β€” Optional annotations documenting expected types - not enforced at runtime

Hints document intent and let tools (IDEs, mypy) catch type mistakes - but Python itself ignores them at runtime: add("a", "b") still runs. -> int hints the return type.

Type hintsmypy

Q28. medium

How do you read a function's docstring?

def area(r):
    """Return the area of a circle with radius r."""
    return 3.14159 * r * r

print(area.__doc__)
help(area)
  1. A help(func) or func.__doc__
  2. B func.doc()
  3. C docstring(func)
  4. D You can't after definition

Answer: A β€” help(func) or func.__doc__

The triple-quoted string right under def is stored in func.__doc__ and shown by help(func). Good docstrings say what the function does, its parameters and return value.

Docstringshelp()

Q29. medium

What is the output? def outer(): def inner(): return "hi" return inner() print(outer())

def outer():
    def inner():
        return "hi"
    return inner()   # calls inner, returns 'hi'

print(outer())        # hi
  1. A hi
  2. B inner
  3. C Error - functions can't nest
  4. D None

Answer: A β€” hi

Functions can be defined INSIDE other functions. outer defines inner, calls it (note the parentheses in 'return inner()'), and returns its result: 'hi'. Returning inner WITHOUT parentheses would return the function itself - that's how closures work (next topics!).

Nested functionsClosures

Hard questions (8)

Q8. hard

Which call is INVALID for def f(a, b)?

f(1, 2)       # ok - all positional
f(1, b=2)     # ok - positional then keyword
# f(a=1, 2)   # SyntaxError!
  1. A f(1, 2)
  2. B f(a=1, b=2)
  3. C f(1, b=2)
  4. D f(a=1, 2)

Answer: D β€” f(a=1, 2)

Positional arguments must come BEFORE keyword arguments. f(a=1, 2) puts a positional after a keyword - SyntaxError: positional argument follows keyword argument.

Argument orderSyntaxError

Q13. hard

What does the key argument do here? words = ["banana", "fig", "apple"] print(sorted(words, key=len))

print(sorted(words, key=len))
# ['fig', 'apple', 'banana']

students = [{"name": "Ana", "marks": 92}, {"name": "Ben", "marks": 85}]
top = sorted(students, key=lambda s: s["marks"], reverse=True)
  1. A ['fig', 'apple', 'banana'] - sorts by word LENGTH
  2. B ['apple', 'banana', 'fig'] - alphabetical
  3. C Removes short words
  4. D Error

Answer: A β€” ['fig', 'apple', 'banana'] - sorts by word LENGTH

key tells sorted() what to compare - here each word's len(): 3, 5, 6 -> fig, apple, banana. Lambdas are common keys: sorted(students, key=lambda s: s["marks"]).

sorted()lambdakey functions

Q16. hard

Why does this raise UnboundLocalError? count = 0 def inc(): count = count + 1 inc()

count = 0
def inc():
    global count
    count += 1     # now legal

# better style:
def inc(count):
    return count + 1
  1. A count doesn't exist at all
  2. B The assignment makes count LOCAL for the whole function, so 'count + 1' reads a local that has no value yet
  3. C Functions can't use numbers
  4. D inc needs a parameter

Answer: B β€” The assignment makes count LOCAL for the whole function, so 'count + 1' reads a local that has no value yet

Because the function ASSIGNS to count, Python treats count as local everywhere in the function - including the right-hand side, where it hasn't been given a value yet. Fix: declare 'global count', or better, pass it in and return the new value.

UnboundLocalErrorglobalScope

Q17. hard

THE classic Python trap - what is the output? def add(item, lst=[]): lst.append(item) return lst print(add(1)) print(add(2))

def add(item, lst=None):
    if lst is None:
        lst = []       # fresh list per call
    lst.append(item)
    return lst
  1. A [1] then [2]
  2. B [1] then [1, 2] - the SAME default list is reused between calls
  3. C [1, 2] then [1, 2]
  4. D Error

Answer: B β€” [1] then [1, 2] - the SAME default list is reused between calls

Default values are created ONCE, at function definition - not per call. Every call without lst shares the same list, which keeps growing. Fix: default to None and create the list inside.

  • Asked in countless interviews - the 'mutable default argument' trap.

Default argumentsMutabilityInterview traps

Q20. hard

Which definition is INVALID?

def f(a, b=2):     # correct order
# def f(a=1, b):   # SyntaxError!
  1. A def f(a, b=2):
  2. B def f(a=1, b):
  3. C def f(a, b=2, c=3):
  4. D def f(*args, **kwargs):

Answer: B β€” def f(a=1, b):

Parameters WITH defaults must come AFTER those without: def f(a=1, b): is a SyntaxError - Python couldn't tell which argument f(5) fills. Required first, optional after.

Default argumentsParameter order

Q22. hard

What happens to a recursive function with NO base case?

def broken(n):
    return broken(n - 1)   # no base case!
# broken(5)   # RecursionError
  1. A It runs forever silently
  2. B RecursionError: maximum recursion depth exceeded
  3. C It returns None
  4. D SyntaxError at definition

Answer: B β€” RecursionError: maximum recursion depth exceeded

Each call stacks up; without a stopping condition Python hits its recursion limit (about 1000 calls) and raises RecursionError - its protection against a true infinite recursion crash.

RecursionErrorCall stack

Q26. hard

What does this show? def shout(text): return text.upper() f = shout print(f("hi"))

f = shout        # no () - the function itself
print(f("hi"))  # HI
ops = [shout, str.lower]  # functions in a list!
  1. A HI - functions are objects that can be assigned to variables
  2. B Error - functions can't be assigned
  3. C hi
  4. D shout

Answer: A β€” HI - functions are objects that can be assigned to variables

Functions are first-class objects: assign them, store them in lists, pass them to other functions. f = shout (NO parentheses) makes f another name for the same function; f("hi") calls it.

  • shout() with parentheses would CALL it; without, you refer to it.

First-class functionsCallbacks

Q27. hard

What is the output? def apply(func, value): return func(value) print(apply(len, "hello"))

def apply(func, value):
    return func(value)

print(apply(len, "hello"))       # 5
print(apply(str.upper, "hi"))    # HI
  1. A 5
  2. B hello
  3. C len
  4. D Error

Answer: A β€” 5

apply receives the len function itself and calls it on "hello" -> 5. Passing functions as arguments is the foundation of callbacks, map(), sorted(key=...), and decorators.

Higher-order functionsCallbacks

Practice β€œFunctions” as a quiz