🕯️ Magic Note
The DRY principle: Don’t Repeat Yourself. Functions are the primary tool for following this principle. If you write the same code more than twice, it probably belongs in a function. Functions also make your code more testable and easier to debug.
- Reusability: Write once, use many times
- Organization: Break complex problems into small pieces
- Readability: Give meaningful names to blocks of code
- Maintainability: Fix a bug in one place, not everywhere
- Testing: Test each function independently
Python
# Without a function (repetitive)
print(“Hello, Alice!”)
print(“Hello, Bob!”)
print(“Hello, Charlie!”)
# With a function (clean and reusable)
def greet(name):
print(f”Hello, {name}!”)
greet(“Alice”)
greet(“Bob”)
greet(“Charlie”)
Python
# Basic function definition
def say_hello():
print(“Hello, world!”)
# Calling the function
say_hello() # Output: Hello, world!
Python
# Function with one parameter
def square(x):
print(x ** 2)
square(5) # 25
square(10) # 100
# Function with multiple parameters
def add(a, b):
print(a + b)
add(3, 5) # 8
add(10, 20) # 30
🕯️ Magic Note
When you define a function, the variables in parentheses are called parameters. When you call a function, the values you pass are called arguments. Many programmers use these terms interchangeably, but the distinction is useful.
Python
# Function that returns a value
def add(a, b):
return a + b
result = add(3, 5)
print(result) # 8
# Function without return returns None
def say_hello(name):
print(f”Hello, {name}!”)
result = say_hello(“Ali”)
print(result) # None
Python
def check_age(age):
if age < 0:
return “Invalid” # Stops here if age < 0
if age >= 18:
return “Adult”
return “Minor”
print(“This never runs”)
print(check_age(-5)) # “Invalid”
print(check_age(20)) # “Adult”
print(check_age(15)) # “Minor”
Python
def get_stats(numbers):
return min(numbers), max(numbers), sum(numbers) / len(numbers)
minimum, maximum, average = get_stats([10, 20, 30, 40, 50])
print(f”Min: {minimum}”) # Min: 10
print(f”Max: {maximum}”) # Max: 50
print(f”Avg: {average}”) # Avg: 30.0
🕯️ Magic Note
Returning multiple values is actually returning a single tuple. Python unpacks it automatically. This is elegant and very Pythonic.
Python
def greet(name, greeting=”Hello”):
print(f”{greeting}, {name}!”)
greet(“Ali”) # Hello, Ali!
greet(“Sara”, “Hi”) # Hi, Sara!
greet(“Reza”, greeting=”Hey”) # Hey, Reza!
# Multiple default parameters
def create_user(name, age=18, city=”Tehran”):
return {“name”: name, “age”: age, “city”: city}
print(create_user(“Ali”))
print(create_user(“Sara”, 25))
print(create_user(“Reza”, city=”Shiraz”))
Python
# Dangerous: mutable default
def add_item(item, my_list=[]):
my_list.append(item)
return my_list
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] (same list!)
# Safe way
def add_item_safe(item, my_list=None):
if my_list is None:
my_list = []
my_list.append(item)
return my_list
Python
def describe_person(name, age, city, job=”Unknown”):
print(f”{name} is {age}, lives in {city}, works as {job}”)
# Positional arguments (order matters)
describe_person(“Ali”, 25, “Tehran”, “Engineer”)
# Keyword arguments (order does not matter)
describe_person(city=”Shiraz”, name=”Sara”, age=30, job=”Doctor”)
# Mixing positional and keyword (positional first)
describe_person(“Reza”, 28, job=”Teacher”, city=”Isfahan”)
Python
# *args collects extra positional arguments as a tuple
def sum_all(*numbers):
return sum(numbers)
print(sum_all(1, 2, 3)) # 6
print(sum_all(10, 20, 30, 40)) # 100
# **kwargs collects extra keyword arguments as a dictionary
def print_info(**info):
for key, value in info.items():
print(f”{key}: {value}”)
print_info(name=”Ali”, age=25, city=”Tehran”)
# Combining both (args first, then kwargs)
def flexible(first, second, *args, **kwargs):
print(f”First: {first}”)
print(f”Second: {second}”)
print(f”Args: {args}”)
print(f”Kwargs: {kwargs}”)
flexible(1, 2, 3, 4, 5, name=”Ali”, age=25)
Python
def calculate_area(length, width):
“””
Calculate the area of a rectangle.
Parameters:
length (float): The length of the rectangle
width (float): The width of the rectangle
Returns:
float: The area of the rectangle
“””
return length * width
# View the docstring
print(calculate_area.__doc__)
# Or use help(calculate_area) in the interpreter
Python
global_var = “I am global”
def my_function():
local_var = “I am local”
print(global_var) # Can read global
print(local_var) # Can read local
my_function()
# print(local_var) # NameError! local_var does not exist outside
Python
def square(x):
return x ** 2
def sum_of_squares(a, b):
return square(a) + square(b)
print(sum_of_squares(3, 4)) # 9 + 16 = 25
Python
# Regular function
def double(x):
return x * 2
# Lambda function (same thing)
double_lambda = lambda x: x * 2
print(double(5)) # 10
print(double_lambda(5)) # 10
# Lambda with multiple arguments
add = lambda a, b: a + b
print(add(3, 5)) # 8
# Commonly used with sorted(), filter(), map()
numbers = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6]
- Forgetting to call the function (writing my_func instead of my_func())
- Using a mutable default parameter (def func(lst=[]))
- Returning something but not capturing it (my_func() instead of result = my_func())
- Trying to modify a global variable without the global keyword
- Indentation errors (the function body must be indented)
- Code after return that never executes
- Write a function called square that returns the square of a number.
- What is the difference between a parameter and an argument?
- What does a function return if there is no return statement?
- How do you write a docstring?
- What is the problem with def add_item(item, items=[])?
- When would you use *args?
⚡ Whisper
A function is a spell you write once and cast many times. You give it a name. You tell it what ingredients to expect (parameters). You write the steps inside. Then you decide what it returns. The function waits patiently. It does nothing until you call its name. Then it springs into action. It takes your ingredients, follows the steps, and hands you the result. This is how you build from simple to complex. You write small functions that do one thing well. Then you combine them. A function for greeting. A function for calculating. A function for validating. Each is a trusted servant. Each knows its job. Together they build programs that are clear, organized, and beautiful. Do not be afraid to create many small functions. They are not overhead. They are clarity.