AiTechWorlds
AiTechWorlds
Functions are the most important concept in all of programming. They're how you stop writing the same code over and over, how you break complex problems into manageable pieces, and how professional code is organized.
If you get functions right, everything else becomes easier.
def greet(name):
message = f"Hello, {name}!"
return message
# Call it
result = greet("Alice")
print(result) # Hello, Alice!
print(greet("Bob")) # Hello, Bob!
The anatomy: def keyword → function name → parameters in parentheses → colon → indented body → optional return.
People use these interchangeably, but there's a distinction worth knowing:
def add(x, y): # x and y are PARAMETERS (in the definition)
return x + y
result = add(3, 5) # 3 and 5 are ARGUMENTS (in the call)
def greet(name, greeting="Hello", punctuation="!"):
return f"{greeting}, {name}{punctuation}"
greet("Alice") # "Hello, Alice!"
greet("Alice", "Hi") # "Hi, Alice!"
greet("Alice", "Hey", ".") # "Hey, Alice."
greet("Alice", punctuation="?") # "Hello, Alice?" (keyword argument)
Rule: Parameters with defaults must come after parameters without defaults.
# Wrong
def bad(x="default", y): # SyntaxError!
pass
# Right
def good(y, x="default"):
pass
A function can return anything — or nothing:
# Return multiple values (actually returns a tuple)
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([3, 1, 4, 1, 5, 9, 2])
print(f"Min: {low}, Max: {high}") # Min: 1, Max: 9
# Return nothing (returns None implicitly)
def log_message(msg):
print(f"[LOG] {msg}") # No return statement
result = log_message("Server started")
print(result) # None
These let functions accept a variable number of arguments:
# *args — variable positional arguments (tuple inside function)
def total(*args):
return sum(args)
print(total(1, 2, 3)) # 6
print(total(10, 20, 30, 40)) # 100
# **kwargs — variable keyword arguments (dict inside function)
def print_info(**kwargs):
for key, value in kwargs.items():
print(f" {key}: {value}")
print_info(name="Alice", age=30, city="NYC")
# name: Alice
# age: 30
# city: NYC
# Combining all types
def flexible(required, *args, **kwargs):
print(f"Required: {required}")
print(f"Extra args: {args}")
print(f"Extra kwargs: {kwargs}")
flexible("must", 1, 2, 3, color="red", size=10)
This trips up many beginners. Python has rules about where a variable can be accessed:
x = "global" # Global scope — accessible everywhere
def outer():
y = "enclosing" # Enclosing scope
def inner():
z = "local" # Local scope — only inside inner()
print(x) # Can access global
print(y) # Can access enclosing
print(z) # Can access local
inner()
# print(z) # NameError! z doesn't exist here
outer()
The LEGB Rule — Python searches for variables in this order:
len, print)count = 0
def increment():
global count # Declare intent to modify global
count += 1
increment()
increment()
print(count) # 2
Tip: Using global is usually a code smell. Prefer passing values as parameters and returning them.
Lambdas are one-line anonymous functions. Use them for simple operations passed to other functions:
# Regular function
def double(x):
return x * 2
# Equivalent lambda
double = lambda x: x * 2
# Most useful when passed directly
numbers = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, numbers))
evens = list(filter(lambda x: x % 2 == 0, numbers))
sorted_names = sorted(["Alice", "bob", "Charlie"], key=lambda s: s.lower())
print(doubled) # [2, 4, 6, 8, 10]
print(evens) # [2, 4]
print(sorted_names) # ['Alice', 'bob', 'Charlie']
def calculate_compound_interest(principal, rate, years):
"""
Calculate compound interest.
Args:
principal: Initial investment amount
rate: Annual interest rate (as decimal, e.g., 0.07 for 7%)
years: Number of years
Returns:
Final amount including interest
"""
return principal * (1 + rate) ** years
help(calculate_compound_interest) # Shows your docstring
def process_student_grades(students):
"""Process student data and return summary statistics."""
grades = [s["grade"] for s in students]
passing = [s for s in students if s["grade"] >= 60]
return {
"total": len(students),
"average": sum(grades) / len(grades),
"pass_rate": len(passing) / len(students) * 100,
"top_student": max(students, key=lambda s: s["grade"])["name"],
}
students = [
{"name": "Alice", "grade": 92},
{"name": "Bob", "grade": 75},
{"name": "Carol", "grade": 55},
{"name": "Dave", "grade": 88},
]
summary = process_student_grades(students)
print(f"Class average: {summary['average']:.1f}")
print(f"Pass rate: {summary['pass_rate']:.0f}%")
print(f"Top student: {summary['top_student']}")
get_user should only get a user, not also send an email.calculate_tax(), get_user(), validate_email() — the name says what it does.Functions are not just a feature of Python — they're the fundamental building block of all software. Master them here, and every language you learn in the future will click faster.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises