Functions in Python
Functions are one of the most important concepts in programming. They allow you to organize your code into reusable blocks, making your programs more modular, readable, and maintainable. Think of functions as mini-programs that perform specific tasks.
What are Functions?
A function is a block of code that:
- Performs a specific task
- Can be called (executed) multiple times
- Can accept input (parameters)
- Can return output (return values)
- Helps avoid code repetition
Real-world analogy: A function is like a recipe. You give it ingredients (parameters), it follows a process, and produces a result (return value).
Defining Your First Function
Basic Function Syntax
def function_name():
"""Optional docstring describing the function"""
# Code to execute
pass # placeholder for empty function
Simple Example
def greet():
"""This function prints a greeting message"""
print("Hello, World!")
print("Welcome to Python functions!")
# Call the function
greet()
Output:
Hello, World!
Welcome to Python functions!
Functions with Parameters
Parameters allow functions to accept input and work with different data:
Single Parameter
def greet_person(name):
"""Greet a specific person"""
print(f"Hello, {name}!")
print("Nice to meet you!")
# Call with different arguments
greet_person("Alice")
greet_person("Bob")
Multiple Parameters
def introduce(name, age, city):
"""Introduce a person with their details"""
print(f"Hi, I'm {name}")
print(f"I'm {age} years old")
print(f"I live in {city}")
# Call with multiple arguments
introduce("Sarah", 25, "New York")
introduce("Mike", 30, "Los Angeles")
Parameter Order Matters
def calculate_rectangle_area(length, width):
area = length * width
print(f"Rectangle: {length} x {width} = {area}")
calculate_rectangle_area(5, 3) # length=5, width=3
calculate_rectangle_area(3, 5) # length=3, width=5 (different result display)
Return Values
Functions can return values using the return statement:
Basic Return
def add_numbers(a, b):
"""Add two numbers and return the result"""
result = a + b
return result
# Use the returned value
sum_result = add_numbers(10, 5)
print(f"10 + 5 = {sum_result}")
# Or use it directly
print(f"7 + 3 = {add_numbers(7, 3)}")
Multiple Return Values
def get_name_parts(full_name):
"""Split a full name into first and last name"""
parts = full_name.split()
first_name = parts[0]
last_name = parts[-1] # Last element
return first_name, last_name
# Unpack the returned tuple
first, last = get_name_parts("John Doe")
print(f"First: {first}, Last: {last}")
Functions with Conditions
def check_even_odd(number):
"""Check if a number is even or odd"""
if number % 2 == 0:
return "even"
else:
return "odd"
# Test the function
print(f"8 is {check_even_odd(8)}")
print(f"7 is {check_even_odd(7)}")
Default Parameters
You can provide default values for parameters:
def greet_with_title(name, title="Mr./Ms."):
"""Greet someone with an optional title"""
print(f"Hello, {title} {name}!")
# Call with default title
greet_with_title("Johnson")
# Call with custom title
greet_with_title("Smith", "Dr.")
greet_with_title("Wilson", "Professor")
Multiple Default Parameters
def create_profile(name, age=25, city="Unknown", country="USA"):
"""Create a user profile with default values"""
print(f"Profile: {name}")
print(f"Age: {age}")
print(f"Location: {city}, {country}")
print("-" * 20)
# Various ways to call
create_profile("Alice")
create_profile("Bob", 30)
create_profile("Charlie", 28, "Seattle")
create_profile("Diana", 35, "Miami", "USA")
Keyword Arguments
You can specify parameters by name when calling functions:
def book_flight(passenger, destination, departure_date, seat_class="Economy"):
print(f"Booking Details:")
print(f"Passenger: {passenger}")
print(f"Destination: {destination}")
print(f"Departure: {departure_date}")
print(f"Class: {seat_class}")
# Using keyword arguments (order doesn't matter)
book_flight(destination="Paris", passenger="John Doe", departure_date="2024-06-15")
book_flight(passenger="Jane Smith", seat_class="Business",
destination="Tokyo", departure_date="2024-07-01")
Variable-Length Arguments
*args (Variable Positional Arguments)
def calculate_sum(*numbers):
"""Calculate sum of any number of arguments"""
total = 0
for num in numbers:
total += num
return total
# Call with different numbers of arguments
print(calculate_sum(1, 2, 3)) # 6
print(calculate_sum(5, 10, 15, 20)) # 50
print(calculate_sum(100)) # 100
**kwargs (Variable Keyword Arguments)
def create_student_record(name, **details):
"""Create a student record with flexible additional details"""
print(f"Student: {name}")
for key, value in details.items():
print(f"{key}: {value}")
print("-" * 15)
# Call with various keyword arguments
create_student_record("Alice", age=20, major="Computer Science", gpa=3.8)
create_student_record("Bob", age=22, major="Mathematics", year="Senior", scholarship=True)
Local vs Global Variables
Local Variables
def calculate_area():
length = 10 # Local variable
width = 5 # Local variable
area = length * width
return area
result = calculate_area()
print(result)
# print(length) # Error: length is not defined outside the function
Global Variables
counter = 0 # Global variable
def increment_counter():
global counter # Declare that we want to modify the global variable
counter += 1
print(f"Counter: {counter}")
increment_counter() # Counter: 1
increment_counter() # Counter: 2
print(f"Final counter: {counter}") # Final counter: 2
Practical Examples
Example 1: Temperature Converter
def celsius_to_fahrenheit(celsius):
"""Convert Celsius to Fahrenheit"""
fahrenheit = (celsius * 9/5) + 32
return fahrenheit
def fahrenheit_to_celsius(fahrenheit):
"""Convert Fahrenheit to Celsius"""
celsius = (fahrenheit - 32) * 5/9
return celsius
def temperature_converter():
"""Interactive temperature converter"""
print("=== Temperature Converter ===")
print("1. Celsius to Fahrenheit")
print("2. Fahrenheit to Celsius")
choice = input("Choose conversion (1 or 2): ")
temp = float(input("Enter temperature: "))
if choice == "1":
result = celsius_to_fahrenheit(temp)
print(f"{temp}°C = {result:.1f}°F")
elif choice == "2":
result = fahrenheit_to_celsius(temp)
print(f"{temp}°F = {result:.1f}°C")
else:
print("Invalid choice!")
# Run the converter
temperature_converter()
Example 2: Password Generator
import random
import string
def generate_password(length=8, include_uppercase=True, include_numbers=True, include_symbols=False):
"""Generate a random password with specified criteria"""
characters = string.ascii_lowercase # Always include lowercase
if include_uppercase:
characters += string.ascii_uppercase
if include_numbers:
characters += string.digits
if include_symbols:
characters += "!@#$%^&*"
password = ''.join(random.choice(characters) for _ in range(length))
return password
# Generate different types of passwords
print("Simple password:", generate_password())
print("Complex password:", generate_password(12, True, True, True))
print("Numbers only:", generate_password(8, False, True, False))
Example 3: Grade Calculator
def calculate_letter_grade(score):
"""Convert numeric score to letter grade"""
if score >= 90:
return 'A'
elif score >= 80:
return 'B'
elif score >= 70:
return 'C'
elif score >= 60:
return 'D'
else:
return 'F'
def calculate_gpa_point(letter_grade):
"""Convert letter grade to GPA points"""
grade_points = {
'A': 4.0, 'B': 3.0, 'C': 2.0, 'D': 1.0, 'F': 0.0
}
return grade_points.get(letter_grade, 0.0)
def process_student_grades(*scores):
"""Process multiple test scores and calculate statistics"""
if not scores:
return "No scores provided"
# Calculate statistics
total = sum(scores)
average = total / len(scores)
highest = max(scores)
lowest = min(scores)
# Get letter grade and GPA
letter_grade = calculate_letter_grade(average)
gpa_points = calculate_gpa_point(letter_grade)
# Return results as a dictionary
return {
'scores': scores,
'average': round(average, 2),
'letter_grade': letter_grade,
'gpa_points': gpa_points,
'highest': highest,
'lowest': lowest
}
# Test the grade calculator
student_results = process_student_grades(85, 92, 78, 88, 95)
print("Grade Report:")
for key, value in student_results.items():
print(f"{key.title()}: {value}")
Function Documentation
Docstrings
def calculate_compound_interest(principal, rate, time, compound_frequency=1):
"""
Calculate compound interest.
Parameters:
principal (float): Initial amount of money
rate (float): Annual interest rate (as decimal, e.g., 0.05 for 5%)
time (int): Number of years
compound_frequency (int): How many times interest is compounded per year
Returns:
float: Final amount after compound interest
Example:
>>> calculate_compound_interest(1000, 0.05, 2)
1102.5
"""
amount = principal * (1 + rate/compound_frequency) ** (compound_frequency * time)
return round(amount, 2)
# Access the docstring
print(calculate_compound_interest.__doc__)
Common Function Patterns
Input Validation
def divide_numbers(a, b):
"""Safely divide two numbers with error handling"""
if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
return "Error: Both arguments must be numbers"
if b == 0:
return "Error: Cannot divide by zero"
return a / b
# Test with various inputs
print(divide_numbers(10, 2)) # 5.0
print(divide_numbers(10, 0)) # Error: Cannot divide by zero
print(divide_numbers(10, "2")) # Error: Both arguments must be numbers
Helper Functions
def is_valid_email(email):
"""Check if email format is valid (simplified)"""
return "@" in email and "." in email
def is_strong_password(password):
"""Check if password meets strength requirements"""
return (len(password) >= 8 and
any(c.isupper() for c in password) and
any(c.isdigit() for c in password))
def register_user(username, email, password):
"""Register a new user with validation"""
if len(username) < 3:
return "Username must be at least 3 characters"
if not is_valid_email(email):
return "Invalid email format"
if not is_strong_password(password):
return "Password must be at least 8 characters with uppercase and number"
return f"User {username} registered successfully!"
# Test user registration
print(register_user("john", "john@email.com", "Password123"))
print(register_user("ab", "invalid-email", "weak"))
Common Mistakes and How to Avoid Them
1. Forgetting to Return Values
# Wrong - function doesn't return anything
def add_wrong(a, b):
result = a + b
print(result) # Only prints, doesn't return
# Correct - function returns the result
def add_correct(a, b):
result = a + b
return result
# Usage
total = add_correct(5, 3) # Now you can use the result
2. Modifying Mutable Default Parameters
# Wrong - dangerous default parameter
def add_item_wrong(item, my_list=[]):
my_list.append(item)
return my_list
# Correct - use None as default
def add_item_correct(item, my_list=None):
if my_list is None:
my_list = []
my_list.append(item)
return my_list
3. Not Understanding Variable Scope
x = 10 # Global variable
def modify_global():
global x # Declare intent to modify global
x = 20
def create_local():
x = 30 # Creates a new local variable
print(f"Local x: {x}")
print(f"Original x: {x}") # 10
create_local() # Local x: 30
print(f"After create_local: {x}") # Still 10
modify_global()
print(f"After modify_global: {x}") # 20
Practice Exercises
Exercise 1: Calculator Functions
Create functions for basic arithmetic operations (add, subtract, multiply, divide) and a main function that uses them.
Exercise 2: Text Analyzer
Write functions to analyze text:
- Count words
- Count vowels
- Check if it's a palindrome
- Convert to title case
Exercise 3: Shopping Cart
Create functions to manage a shopping cart:
- Add items
- Remove items
- Calculate total
- Apply discounts
Sample Solutions
Exercise 1:
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
return "Cannot divide by zero"
return a / b
def calculator():
print("Simple Calculator")
num1 = float(input("Enter first number: "))
operation = input("Enter operation (+, -, *, /): ")
num2 = float(input("Enter second number: "))
if operation == '+':
result = add(num1, num2)
elif operation == '-':
result = subtract(num1, num2)
elif operation == '*':
result = multiply(num1, num2)
elif operation == '/':
result = divide(num1, num2)
else:
result = "Invalid operation"
print(f"Result: {result}")
calculator()
Exercise 2:
def count_words(text):
return len(text.split())
def count_vowels(text):
vowels = "aeiouAEIOU"
return sum(1 for char in text if char in vowels)
def is_palindrome(text):
cleaned = ''.join(char.lower() for char in text if char.isalnum())
return cleaned == cleaned[::-1]
def to_title_case(text):
return text.title()
def analyze_text(text):
print(f"Text Analysis for: '{text}'")
print(f"Word count: {count_words(text)}")
print(f"Vowel count: {count_vowels(text)}")
print(f"Is palindrome: {is_palindrome(text)}")
print(f"Title case: {to_title_case(text)}")
# Test
analyze_text("A man a plan a canal Panama")
Key Takeaways
- Functions help organize code into reusable, modular pieces
- Use
defto define functions andreturnto send values back - Parameters allow functions to work with different inputs
- Default parameters provide flexibility in function calls
- Local variables exist only within the function
- Good function names and docstrings make code self-documenting
- Functions should generally do one thing well (single responsibility)
What's Next?
Now that you understand functions, you're ready to explore:
- Lists and Tuples - Working with collections of data
- Dictionaries and Sets - Key-value pairs and unique collections
- Object-Oriented Programming - Organizing code with classes
Functions are the building blocks of well-organized programs. Practice creating functions for different tasks to improve your programming skills!
