Language:

Search

Python Functions: Arguments, Returns, Scope, Lambdas & Recursion

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: LocalEnclosing (in nested functions) → GlobalBuilt-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 with return.
  • Arguments: positional, keyword, default values; expand with *args and **kwargs.
  • Return multiple values via tuples and unpacking.
  • Understand scope (LEGB): use global/nonlocal carefully.
  • Functions are first-class: pass, store, and return them.
  • Use lambdas for tiny one-liners; prefer def otherwise.
  • Recursion needs a base case; loops are often simpler and faster.

Next up: Data Structures — lists, tuples, sets, dictionaries, and comprehensions.

Previous: Control Flow

Ahmad Ali

Ahmad Ali

Leave a comment

Your email address will not be published. Required fields are marked *

Your experience on this site will be improved by allowing cookies Cookie Policy