Functions let you organize code into reusable blocks. In this lesson, you’ll learn how to define functions, pass arguments in different ways, return values, understand scope, use small anonymous functions (lambdas), and see a friendly introduction to recursion.
1) Defining a Function
Use def to define a function. It may take inputs (parameters) and may return a value with return.
def greet(name):
print(f"Hello, {name}!")
greet("Ali") # Hello, Ali!
Returning a value
def add(a, b):
return a + b
result = add(2, 3)
print(result) # 5
Docstrings (recommended): describe what the function does.
def area_of_circle(r):
"""Return the area of a circle of radius r."""
PI = 3.14159
return PI * (r ** 2)
2) Arguments & Parameters
There are several ways to pass data into functions.
a) Positional arguments
def power(base, exponent):
return base ** exponent
print(power(2, 3)) # 8
b) Keyword arguments
print(power(exponent=3, base=2)) # 8 (order doesn't matter when using keywords)
c) Default values
def welcome(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(welcome("Ammar")) # Hello, Ammar!
print(welcome("Ammar", greeting="Hi")) # Hi, Ammar!
d) Variable arguments: *args and **kwargs
*args collects extra positional arguments as a tuple; **kwargs collects extra keyword arguments as a dict.
def summarize(title, *items, **options):
line = f"{title}: " + ", ".join(str(x) for x in items)
if options.get("uppercase"):
line = line.upper()
return line
print(summarize("Fruits", "apple", "banana", "mango"))
print(summarize("Fruits", "apple", uppercase=True))
Parameter order tip: def f(positional, /, standard, *, keyword_only): is advanced syntax. For now, remember: normal params → *args → **kwargs.
3) Multiple Returns & Unpacking
Functions can return a tuple; unpack it on the left.
def min_max(values):
return min(values), max(values)
lo, hi = min_max([3, 7, 2, 9])
print(lo, hi) # 2 9
4) Scope: Local, Enclosing, Global
Python looks up names using the LEGB rule: Local → Enclosing (in nested functions) → Global → Built-in.
a) Local vs Global
x = 10 # global
def show():
x = 5 # local (different from global x)
print("inside:", x)
show()
print("outside:", x)
# inside: 5
# outside: 10
b) global (modify a global — use sparingly)
count = 0
def increment():
global count
count += 1
increment()
print(count) # 1
c) nonlocal (modify the nearest enclosing scope)
def outer():
total = 0
def inner():
nonlocal total
total += 1
return total
print(inner()) # 1
print(inner()) # 2
outer()
5) Functions as First-Class Objects
You can store functions in variables, pass them to other functions, and return them.
def square(x):
return x * x
def apply(fn, value):
return fn(value)
op = square
print(apply(op, 5)) # 25
6) Lambdas (Small Anonymous Functions)
Use lambdas for tiny throwaway functions.
# sort by length
words = ["kiwi", "banana", "fig", "apple"]
print(sorted(words, key=lambda w: len(w)))
# map & filter
nums = [1, 2, 3, 4, 5]
doubles = list(map(lambda n: n * 2, nums))
evens = list(filter(lambda n: n % 2 == 0, nums))
print(doubles) # [2, 4, 6, 8, 10]
print(evens) # [2, 4]
Tip: Prefer def for anything non-trivial; lambdas are limited to a single expression.
7) Recursion (Optional)
A recursive function calls itself. Always define a base case to stop.
a) Factorial
def factorial(n):
if n <= 1: # base case
return 1
return n * factorial(n - 1)
print(factorial(5)) # 120
b) Fibonacci (illustrative)
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
print(fib(6)) # 8
Note: Recursion can be slower or hit recursion limits; many tasks are better done with loops.
8) Practical Mini-Examples
a) Safe average
def average(values):
if not values:
return 0.0
return sum(values) / len(values)
print(average([10, 20, 30])) # 20.0
print(average([])) # 0.0
b) Flexible greeting with *args / **kwargs
def make_greeting(*names, prefix="Hello"):
joined = ", ".join(names) if names else "friend"
return f"{prefix}, {joined}!"
print(make_greeting("Ali", "Ammar"))
print(make_greeting(prefix="Hi"))
c) Using a function as a key
def last_char(s):
return s[-1]
cities = ["Lahore", "Karachi", "Quetta", "Multan"]
print(sorted(cities, key=last_char)) # sort by last letter
Key Takeaways
- Define functions with
def; return values withreturn. - Arguments: positional, keyword, default values; expand with
*argsand**kwargs. - Return multiple values via tuples and unpacking.
- Understand scope (LEGB): use
global/nonlocalcarefully. - Functions are first-class: pass, store, and return them.
- Use lambdas for tiny one-liners; prefer
defotherwise. - Recursion needs a base case; loops are often simpler and faster.
Next up: Data Structures — lists, tuples, sets, dictionaries, and comprehensions.
Previous: Control Flow
Leave a comment
Your email address will not be published. Required fields are marked *
