A function in Python is a reusable block of code that performs a specific task. Think of it as a mini-program within your program. You define a function once, and then you can call (use) it as many times as needed.
Why Functions Matter:
- Organize code into manageable parts
- Avoid repetition (DRY: Don’t Repeat Yourself)
- Improve readability and reusability
- Enable collaboration in larger projects
🔧 Basic Function Syntax in Python
Here’s the standard way to write a function in Python:
pythonCopyEditdef greet(name): # 'def' keyword starts a function definition
print(f"Hello, {name}!") # Indented code is the function body
Key parts:
def: Keyword that starts the function definitiongreet: Function name (must follow naming rules)name: Parameter inside parentheses:: Ends the function signature line- Indentation: Required (usually 4 spaces) for the function body
return: Sends a result back to the caller (optional)
Function naming rules:
- Use lowercase letters, numbers, and underscores (e.g.,
calculate_area) - Must start with a letter or underscore (not a number)
- Avoid Python keywords (like
if,class,return)
🎯 Function Parameters: The Complete Breakdown
Functions can take inputs, called parameters, to customize their behavior.
1. Positional Parameters
Order matters. Values are matched by position.
pythonCopyEditdef add(a, b):
return a + b
add(3, 5) # a = 3, b = 5
2. Keyword Parameters
You specify which value goes to which parameter using names.
pythonCopyEditadd(a=3, b=5) # Same result as above
3. Default Values
Provides a default if no value is passed.
pythonCopyEditdef greet(name="Guest"):
print(f"Hello, {name}!")
greet() # Hello, Guest!
greet("Alice") # Hello, Alice!
4. Arbitrary Positional Arguments (*args)
Allows any number of extra positional arguments.
pythonCopyEditdef total(*numbers):
return sum(numbers)
total(1, 2, 3, 4) # 10
5. Arbitrary Keyword Arguments (**kwargs)
Collects extra keyword arguments into a dictionary.
pythonCopyEditdef describe_person(**info):
print(info)
describe_person(name="Tom", age=30)
# Output: {'name': 'Tom', 'age': 30}
6. Type Hints (Optional but Helpful)
Clarifies what types are expected.
pythonCopyEditdef square(x: int) -> int:
return x * x
🧠 Scope and Lifetime of Variables
Variables behave differently depending on where they are defined.
1. Local vs. Global
- Local: Defined inside a function—only usable there.
- Global: Defined outside all functions—usable anywhere (with care).
pythonCopyEditx = 10 # Global
def show():
x = 5 # Local
print(x) # 5
2. nonlocal Keyword
Accesses variables from the nearest enclosing function scope (not global).
pythonCopyEditdef outer():
x = "outer"
def inner():
nonlocal x
x = "inner"
inner()
print(x) # inner
3. LEGB Rule (Lookup order):
- Local
- Enclosing
- Global
- Built-in
🎁 Return Values
A function can return values to the caller using return.
1. Single Value
pythonCopyEditdef double(n):
return n * 2
2. Multiple Values (as a Tuple)
pythonCopyEditdef stats(numbers):
return min(numbers), max(numbers)
low, high = stats([4, 7, 1, 9]) # Tuple unpacking
3. No Return = None
pythonCopyEditdef say_hello():
print("Hi!")
result = say_hello() # result is None
4. Early Return
pythonCopyEditdef divide(a, b):
if b == 0:
return "Cannot divide by zero"
return a / b
🎲 First-Class & Higher-Order Functions
First-Class: Functions can be assigned to variables, passed around, or returned.
pythonCopyEditdef shout(msg):
return msg.upper()
s = shout
print(s("hello")) # HELLO
Higher-Order: Functions that take other functions as arguments or return them.
pythonCopyEditdef apply(func, value):
return func(value)
apply(str.upper, "hello") # HELLO
🧬 Lambda (Anonymous) Functions
Short, one-line functions—great for small tasks.
pythonCopyEditsquare = lambda x: x * x
print(square(5)) # 25
Useful with map(), filter(), and sorted():
pythonCopyEditnums = [1, 2, 3, 4]
squares = list(map(lambda x: x**2, nums))
🏷️ Decorators
A decorator is a function that wraps another function to add behavior.
Basic Example:
pythonCopyEditdef debug(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@debug
def greet(name):
print(f"Hello, {name}")
Built-in Decorators:
@staticmethod@classmethod@property
🔁 Recursion vs. Iteration
Recursion: Function calls itself. Needs a base case.
pythonCopyEditdef factorial(n):
if n == 0:
return 1
return n * factorial(n - 1)
Iteration: Uses loops.
pythonCopyEditdef factorial(n):
result = 1
for i in range(1, n+1):
result *= i
return result
Tips:
- Watch out for maximum recursion depth
- Use
functools.lru_cacheto cache recursive calls
pythonCopyEditfrom functools import lru_cache
@lru_cache
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
🧾 Documentation and Readability
Docstrings:
pythonCopyEditdef greet(name):
"""Print a greeting to the user by name."""
print(f"Hello, {name}!")
Follow PEP 8:
- Function names:
lowercase_with_underscores - Keep lines ≤ 79 characters
- Leave 2 blank lines before function definitions
⚠️ Common Pitfalls & Debugging Tips
- Mutable Default Arguments
pythonCopyEditdef append_to_list(value, my_list=[]): # ⚠️ Bad
my_list.append(value)
return my_list
✅ Use None instead:
pythonCopyEditdef append_to_list(value, my_list=None):
if my_list is None:
my_list = []
my_list.append(value)
return my_list
- Namespace Collisions: Don’t reuse variable names unnecessarily.
- Unintended Shadowing: Local variable with the same name as global can confuse behavior.
🧠 [Advanced Optional] Topics
- Generators: Use
yieldinstead ofreturnfor lazy evaluation - Closures: Functions that remember variables from their creation environment
- Partial Functions: Fix some arguments with
functools.partial - Coroutines (
async def): For non-blocking async programming
✅ Best Practices & Real-World Checklist
✔ Checklist for Clean Functions:
- One purpose per function
- Clear and descriptive name
- Includes a docstring
- Uses type hints (if applicable)
- Avoids global state
- Handles errors gracefully (e.g., early returns)
🏁 Real-World Example:
pythonCopyEditdef send_email(to: str, subject: str, body: str) -> bool:
"""Simulate sending an email. Returns True if successful."""
if not to:
return False
print(f"To: {to}\nSubject: {subject}\n\n{body}")
return True
📘 Conclusion
Functions are the backbone of structured Python programming. Mastering them not only improves your code quality but also makes you a better problem solver.