Lesson 10 of 12

Python Functions

A function is a named block of code that does one job. You write it once and call it whenever you need that job done. You have already called many built-in functions, such as print(), len() and sorted(). In this lesson you will write your own Python functions. Functions keep programs short, make them easier to test, and give a clear name to each step of your logic.

Defining and calling Python functions

Start with the keyword def, then the function name, brackets with any parameters, and a colon. The indented block below is the function body. Defining a function does not run it; the body runs only when you call the function by name with brackets.

Most functions send a result back with return. The caller can store that value, print it or pass it to another function. A function without return gives back None. As soon as return runs, the function ends.

def add_gst(amount, rate):
    """Return the amount including GST at the given percentage."""
    return amount + amount * rate / 100

laptop = add_gst(50000, 18)
print(laptop)
print(add_gst(250, 5))

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

result = greet("Selvi")
print(result)
Output
59000.0
262.5
Vanakkam, Selvi!
None

The text in triple quotes under the def line is a docstring. It documents what the function does, and editors show it when you hover over the function name. Writing one line of docstring for every function is a good habit.

Watch out: Printing is not returning. greet() prints a message but returns None, which is why the last line shows None. If other code needs the result, use return.

Parameters and arguments

Parameters are the names in the def line; arguments are the actual values you pass in a call. Python offers several ways to pass them:

FeatureExampleUse it when
Positional argumentsadd_gst(500, 18)There are only one or two obvious values
Keyword argumentsadd_gst(amount=500, rate=18)You want the call to explain itself
Default valuesdef add_gst(amount, rate=18):A parameter usually has the same value
*argsdef total(*prices):The number of values varies
**kwargsdef profile(**details):You want any number of named values
def ticket_price(base, age, is_student=False):
    if age >= 60:
        return base // 2
    if is_student:
        return base - 50
    return base

print(ticket_price(300, 35))
print(ticket_price(300, 20, is_student=True))
print(ticket_price(age=65, base=300))

def bill_total(*prices, discount=0):
    subtotal = sum(prices)
    return subtotal - subtotal * discount / 100

print(bill_total(120, 80, 300))
print(bill_total(120, 80, 300, discount=10))

def profile(name, **details):
    print(name, details)

profile("Gowri", city="Erode", role="designer")
Output
300
250
150
500.0
450.0
Gowri {'city': 'Erode', 'role': 'designer'}

Parameters with defaults must come after those without. Inside the function, *prices arrives as a tuple and **details as a dictionary. Any parameter written after *args, such as discount, can only be passed by keyword, which prevents mix-ups.

Scope: local and global variables

Variables created inside a function are local: they exist only while the function runs and cannot be seen outside it. This is a good thing, because two functions can each use a variable called total without interfering. A function can read a variable defined at the top level of the file, but assigning to that name inside the function creates a new local variable instead. The keyword global changes this, but it makes code harder to follow. It is better to pass values in as arguments and send results out with return.

Returning several values

A function can return several values separated by commas. Python packs them into a tuple, and the caller can unpack them straight into variables, as you learnt in Python Lists and Tuples.

def marks_report(marks: list[int]) -> tuple[int, int, float]:
    """Return the lowest, highest and average mark."""
    return min(marks), max(marks), sum(marks) / len(marks)

low, high, avg = marks_report([68, 91, 74, 85])
print(f"Low {low}, high {high}, average {avg:.1f}")

products = [("Saree", 2499), ("Dhoti", 650), ("Kurta", 1199)]
by_price = sorted(products, key=lambda item: item[1])
print(by_price)
Output
Low 68, high 91, average 79.5
[('Dhoti', 650), ('Kurta', 1199), ('Saree', 2499)]

Type hints

marks: list[int] and -> tuple[int, int, float] are type hints. They describe what the function expects and returns. Python does not enforce them when the code runs, but editors use them to catch mistakes and to offer better suggestions. They are optional, so add them where they make the code clearer.

lambda: tiny anonymous functions

lambda item: item[1] is a one-line function without a name. It takes item and returns item[1]. Lambdas are mainly used as the key for sorted(), min() and max(). If the logic needs more than one simple expression, write a normal def function.

Watch out: Never use a mutable value such as a list as a default: def add_item(item, cart=[]):. The default list is created once and shared between calls, so items pile up unexpectedly. Use cart=None and create a new list inside the function when cart is None.

Tip: Good names for Python functions are verbs that describe the job: calculate_emi(), send_invoice(), is_valid_pincode(). If you struggle to name a function, it may be doing too many jobs; split it into smaller ones.

Further reading

Key takeaways

  • Define functions with def name(params): and call them with name(args).
  • return sends a value back and ends the function; without it the result is None.
  • Use default values, keyword arguments, *args and **kwargs for flexible calls.
  • Variables inside a function are local; pass data in with arguments and out with return.
  • Add a docstring, use light type hints, and keep lambda for short key functions.

Quick quiz

Check what you learned – pick an answer.

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

2. def area(l, w=10): return l * w. What is area(3)?

3. Inside def total(*prices):, what type is prices?

Practice exercise

Write a function emi(principal, annual_rate, months) that returns the monthly loan instalment using the formula P × r × (1 + r)^n / ((1 + r)^n − 1), where r is the monthly rate (annual rate ÷ 12 ÷ 100). Print the EMI for ₹5,00,000 at 9% for 60 months, rounded to 2 decimals.

Show a hint

Calculate r first, then (1 + r) ** months once and reuse it. Return the value; do the rounding when printing.

Show the solution
def emi(principal, annual_rate, months):
    """Return the monthly instalment for a loan."""
    r = annual_rate / 12 / 100
    growth = (1 + r) ** months
    return principal * r * growth / (growth - 1)

print(f"EMI: ₹{emi(500000, 9, 60):,.2f}")

Progress is saved in this browser only.