Functions & modules

A function packages logic under a name so you can run it many times with different inputs. Functions turn a long script into small, testable pieces — the difference between code you write once and code a team can maintain.

Defining and calling

def gst_total(amount: float, rate: float = 18.0) -> float:
    """Return amount including GST."""
    return round(amount * (1 + rate / 100), 2)

print(gst_total(1000))                    # 1180.0
print(gst_total(1000, 5))                 # 1050.0
print(gst_total(rate=12, amount=2000))    # 2240.0 - keyword arguments, any order

amount and rate are parameters; the values you pass are arguments. rate: float = 18.0 supplies a default, so the caller may omit it. The type hints (: float, -> float) document intent for readers and editors; Python does not enforce them at runtime. The text between triple quotes is the docstring, shown by help(gst_total).

Returning values

A function without return gives back None. You can return several values as a tuple and unpack them:

def split_bill(total, people):
    share = total // people
    remainder = total % people
    return share, remainder

each, extra = split_bill(2575, 4)
print(each, extra)      # 643 3

args and *kwargs

def summary(*numbers, **options):
    total = sum(numbers)
    return f"{options.get('label', 'Total')}: {total}"

print(summary(1, 2, 3, label="Sum"))      # Sum: 6

*numbers collects extra positional arguments into a tuple; **options collects named ones into a dict.

Scope

Names created inside a function are local and disappear when it returns. A function can read a module-level name, but assigning to one creates a new local name unless you declare global. Prefer passing values in and returning results out — that keeps functions predictable and easy to test.

Modules

Split code into files and import them:

# utils.py
GST_RATE = 18

def slugify(text):
    return text.lower().replace(" ", "-")

# main.py
from utils import slugify, GST_RATE
import utils                              # then call utils.slugify(...)

print(slugify("Kaju Katli Special"))      # kaju-katli-special

Add a guard so a file can be both imported and run:

if __name__ == "__main__":
    print(slugify("test run"))

The guarded code runs only when you execute python utils.py directly, never when another file imports it.

The standard library and pip

Module Use
datetime dates, times and differences
json / csv read and write data files
pathlib file and folder paths
random sampling and shuffling
statistics mean, median, stdev
math sqrt, ceil, floor, pi

Install third-party packages with pip install package-name inside a virtual environment created by python -m venv .venv, then record them with pip freeze > requirements.txt so a colleague can reproduce your setup.

Common mistakes

  • Forgetting to return, so the caller silently receives None.
  • Using a mutable default such as def add(x, items=[]); use None and create the list inside.
  • Naming your file json.py or random.py, which shadows the standard library module.
  • Writing one 200-line function instead of four short ones; if you cannot name it in a few words, split it.

Practice

Create billing.py with gst_total(amount, rate=18), apply_discount(amount, percent) and invoice_line(item, qty, price) that returns a formatted string. Import all three into main.py, print three invoice lines for a textile order, and add an if __name__ == "__main__" self-test inside billing.py.

B

Written by Bablu Kumar Jha

Founder, BeeProton AI · Mumbai, Maharashtra, India