Comments are text in your code that Python ignores when running the program. They're written for humans to read and understand what the code does. Good comments make your code easier to understand, maintain, and debug.
Think of comments as notes you leave for yourself and other programmers. When you return to your code weeks or months later, comments help you remember what you were thinking.
example:
# This is a comment - Python ignores this line
print("Hello, World!") # This comment explains what this line does
Use the hash symbol (#
) to create single-line comments:
# This is a single-line comment
print("Learning Python")
age = 25 # Variable to store user's age
name = "Emma" # Store the user's name
# You can use multiple single-line comments
# to create a block of explanatory text
# like this paragraph explaining the next section
total_score = 0
Python doesn't have official multi-line comment syntax, but there are two common approaches:
# Method 1: Multiple single-line comments
# This is a longer explanation that spans
# multiple lines. Each line starts with #
# to indicate it's a comment.
# Method 2: Triple quotes (not technically comments, but often used this way)
"""
This is a multi-line string that can serve as a comment.
It's often used for documentation at the beginning of files,
functions, or classes. Python doesn't execute this as code
when it's not assigned to a variable.
"""
def calculate_area(length, width):
"""
Calculate the area of a rectangle.
This type of multi-line comment is called a docstring
and is used to document functions and classes.
"""
return length * width
Comments that appear on the same line as code:
radius = 5 # Circle radius in meters
pi = 3.14159 # Approximation of pi
area = pi * radius ** 2 # Calculate circle area using formula πr²
# Good inline comments are short and relevant
temperature = 72 # Fahrenheit
humidity = 65 # Percentage
# Avoid obvious inline comments
x = 5 # Bad: assign 5 to x (this is obvious)
user_count = 0 # Good: initialize counter for active users
# Explain WHY you're doing something, not just WHAT
import math
def calculate_monthly_payment(principal, rate, years):
"""Calculate monthly mortgage payment"""
# Convert annual rate to monthly and percentage to decimal
monthly_rate = rate / 100 / 12
# Convert years to months
total_months = years * 12
# Use mortgage payment formula
# M = P * [r(1+r)^n] / [(1+r)^n - 1]
if monthly_rate == 0: # Handle case where rate is 0%
return principal / total_months
payment = principal * (monthly_rate * (1 + monthly_rate) ** total_months) / \
((1 + monthly_rate) ** total_months - 1)
return payment
def find_prime_numbers(limit):
"""Find all prime numbers up to the given limit using Sieve of Eratosthenes"""
# Create a list to track which numbers are prime
# Initially assume all numbers are prime (True)
is_prime = [True] * (limit + 1)
is_prime[0] = is_prime[1] = False # 0 and 1 are not prime
# Start with the first prime number, 2
current = 2
while current * current <= limit:
if is_prime[current]:
# Mark all multiples of current as not prime
# Start from current² because smaller multiples
# have already been marked by smaller primes
for multiple in range(current * current, limit + 1, current):
is_prime[multiple] = False
current += 1
# Collect all numbers that remained marked as prime
primes = [num for num in range(2, limit + 1) if is_prime[num]]
return primes
def calculate_age(birth_year):
"""
Calculate age based on birth year.
Assumptions:
- Current year is 2025
- Birth year is valid (not in the future)
- Age calculation doesn't account for exact birth date
"""
current_year = 2025
# Simple age calculation - may be off by 1 year
# depending on whether birthday has occurred this year
age = current_year - birth_year
return age
# Bad examples - these comments state the obvious
x = 5 # Assign 5 to x
y = x + 1 # Add 1 to x and store in y
print(y) # Print the value of y
# Better - explain the purpose, not the mechanics
base_price = 5 # Product base price in dollars
final_price = base_price + 1 # Add shipping cost
print(final_price) # Display total cost to user
# Bad - using comments to explain confusing code
def process_data(d):
# Check if d is not empty and has the right structure
if d and len(d) > 0 and 'items' in d and d['items']:
# Loop through items and calculate totals
t = 0
for i in d['items']:
if 'price' in i and 'quantity' in i:
t += i['price'] * i['quantity']
return t
return 0
# Better - write clear code that doesn't need explanation
def calculate_order_total(order):
"""Calculate the total cost of an order."""
if not order or 'items' not in order:
return 0
total = 0
for item in order['items']:
if 'price' in item and 'quantity' in item:
total += item['price'] * item['quantity']
return total
# Poor readability
def calc(p, r, t):
return p * (1 + r) ** t
# Good readability
def calculate_compound_interest(principal, interest_rate, time_years):
"""Calculate compound interest using the formula A = P(1 + r)^t"""
return principal * (1 + interest_rate) ** time_years
# Usage example
initial_investment = 1000 # dollars
annual_rate = 0.05 # 5% per year
investment_period = 10 # years
final_amount = calculate_compound_interest(
initial_investment,
annual_rate,
investment_period
)
print(f"After {investment_period} years: ${final_amount:.2f}")
# Hard to read - everything in one line
def is_valid_email(email):
return '@' in email and '.' in email.split('@')[1] and len(email.split('@')) == 2
# More readable - broken into steps with descriptive variables
def is_valid_email(email):
"""Check if an email address has basic valid format."""
# Basic checks for email structure
has_at_symbol = '@' in email
parts = email.split('@')
has_exactly_one_at = len(parts) == 2
if not (has_at_symbol and has_exactly_one_at):
return False
# Check the domain part
domain = parts[1]
has_dot_in_domain = '.' in domain
return has_dot_in_domain
# Inconsistent formatting - hard to read
def process_students(students):
for student in students:
if student['grade']>=90:
student['letter_grade']='A'
elif student['grade']>=80:
student['letter_grade']='B'
elif student['grade']>=70:
student['letter_grade']='C'
else:student['letter_grade']='F'
# Consistent formatting - much easier to read
def process_students(students):
"""Assign letter grades based on numeric grades."""
for student in students:
grade = student['grade']
if grade >= 90:
student['letter_grade'] = 'A'
elif grade >= 80:
student['letter_grade'] = 'B'
elif grade >= 70:
student['letter_grade'] = 'C'
else:
student['letter_grade'] = 'F'
def calculate_tip(bill_amount, tip_percentage):
"""
Calculate the tip amount for a restaurant bill.
Args:
bill_amount (float): The total bill amount in dollars
tip_percentage (float): The tip percentage (e.g., 15 for 15%)
Returns:
float: The tip amount in dollars
Example:
>>> calculate_tip(50.0, 20)
10.0
"""
return bill_amount * (tip_percentage / 100)
def analyze_grades(grades):
"""
Analyze a list of student grades and return statistics.
This function calculates various statistics including average,
highest grade, lowest grade, and grade distribution.
Args:
grades (list): List of numeric grades (0-100)
Returns:
dict: Dictionary containing:
- 'average': Mean grade
- 'highest': Highest grade
- 'lowest': Lowest grade
- 'passing_count': Number of grades >= 60
- 'failing_count': Number of grades < 60
Raises:
ValueError: If grades list is empty
TypeError: If grades contains non-numeric values
Example:
>>> grades = [85, 92, 78, 96, 88]
>>> stats = analyze_grades(grades)
>>> print(stats['average'])
87.8
"""
if not grades:
raise ValueError("Grades list cannot be empty")
# Validate that all grades are numbers
for grade in grades:
if not isinstance(grade, (int, float)):
raise TypeError("All grades must be numeric")
# Calculate statistics
average = sum(grades) / len(grades)
highest = max(grades)
lowest = min(grades)
passing_count = sum(1 for grade in grades if grade >= 60)
failing_count = len(grades) - passing_count
return {
'average': average,
'highest': highest,
'lowest': lowest,
'passing_count': passing_count,
'failing_count': failing_count
}
# Student Management System
# Constants
PASSING_GRADE = 60
MAX_GRADE = 100
MIN_GRADE = 0
# Data validation functions
def is_valid_grade(grade):
"""Check if a grade is within valid range."""
return MIN_GRADE <= grade <= MAX_GRADE
def is_valid_student_id(student_id):
"""Check if student ID format is valid."""
return isinstance(student_id, str) and len(student_id) == 8
# Grade calculation functions
def calculate_letter_grade(numeric_grade):
"""Convert numeric grade to letter grade."""
if numeric_grade >= 90:
return 'A'
elif numeric_grade >= 80:
return 'B'
elif numeric_grade >= 70:
return 'C'
elif numeric_grade >= 60:
return 'D'
else:
return 'F'
def calculate_gpa(grades):
"""Calculate GPA from list of letter grades."""
grade_points = {'A': 4.0, 'B': 3.0, 'C': 2.0, 'D': 1.0, 'F': 0.0}
if not grades:
return 0.0
total_points = sum(grade_points[grade] for grade in grades)
return total_points / len(grades)
# Main processing functions
def process_student(student_data):
"""Process individual student data and return formatted results."""
student_id = student_data['id']
name = student_data['name']
grades = student_data['grades']
# Validate input data
if not is_valid_student_id(student_id):
raise ValueError(f"Invalid student ID: {student_id}")
# Calculate letter grades
letter_grades = []
for grade in grades:
if is_valid_grade(grade):
letter_grades.append(calculate_letter_grade(grade))
else:
raise ValueError(f"Invalid grade: {grade}")
# Calculate final statistics
average_grade = sum(grades) / len(grades)
gpa = calculate_gpa(letter_grades)
return {
'id': student_id,
'name': name,
'grades': grades,
'letter_grades': letter_grades,
'average': average_grade,
'gpa': gpa
}
def create_student_report(students):
"""Generate a comprehensive student report."""
# Initialize report data
total_students = len(students)
passing_students = 0
grade_totals = []
print("="*50)
print(" STUDENT GRADE REPORT")
print("="*50)
print()
# Process each student
for student in students:
name = student['name']
grades = student['grades']
average = sum(grades) / len(grades)
# Determine if student is passing
if average >= PASSING_GRADE:
passing_students += 1
status = "PASSING"
else:
status = "FAILING"
# Add to totals for class statistics
grade_totals.extend(grades)
# Print individual student report
print(f"Student: {name}")
print(f"Grades: {grades}")
print(f"Average: {average:.1f}")
print(f"Status: {status}")
print("-" * 30)
# Calculate and display class statistics
class_average = sum(grade_totals) / len(grade_totals)
passing_rate = (passing_students / total_students) * 100
print()
print("CLASS STATISTICS:")
print(f"Total Students: {total_students}")
print(f"Class Average: {class_average:.1f}")
print(f"Passing Rate: {passing_rate:.1f}%")
print("="*50)
def quicksort(arr):
"""
Sort an array using the quicksort algorithm.
Time Complexity: O(n log n) average case, O(n²) worst case
Space Complexity: O(log n) average case
"""
# Base case: arrays with 0 or 1 element are already sorted
if len(arr) <= 1:
return arr
# Choose pivot (middle element for better average performance)
pivot_index = len(arr) // 2
pivot = arr[pivot_index]
# Partition the array around the pivot
# Elements less than pivot go to left partition
left = [x for x in arr if x < pivot]
# Elements equal to pivot (handles duplicates)
middle = [x for x in arr if x == pivot]
# Elements greater than pivot go to right partition
right = [x for x in arr if x > pivot]
# Recursively sort partitions and combine
return quicksort(left) + middle + quicksort(right)
def clean_customer_data(raw_data):
"""
Clean and validate customer data from CSV import.
Common issues addressed:
- Extra whitespace in names and addresses
- Invalid email formats
- Phone numbers in different formats
- Missing required fields
"""
cleaned_customers = []
for customer in raw_data:
# Skip customers with missing critical information
if not customer.get('email') or not customer.get('name'):
continue # Log this in a real application
# Standardize name formatting
name = customer['name'].strip().title()
# Clean and validate email
email = customer['email'].strip().lower()
if '@' not in email or '.' not in email:
continue # Skip invalid emails
# Standardize phone number format
# Remove all non-digit characters, then format
phone = ''.join(filter(str.isdigit, customer.get('phone', '')))
if len(phone) == 10:
# Format as (XXX) XXX-XXXX
phone = f"({phone[:3]}) {phone[3:6]}-{phone[6:]}"
else:
phone = None # Invalid phone number
# Create cleaned customer record
cleaned_customer = {
'name': name,
'email': email,
'phone': phone,
'address': customer.get('address', '').strip()
}
cleaned_customers.append(cleaned_customer)
return cleaned_customers
def process_order(order):
"""Process a customer order."""
# TODO: Add inventory check before processing
# TODO: Implement discount calculation
# TODO: Add email confirmation after successful order
# Basic order validation
if not order.get('items'):
raise ValueError("Order must contain at least one item")
total = 0
for item in order['items']:
# FIXME: This doesn't handle missing price gracefully
total += item['price'] * item['quantity']
# HACK: Temporary 5% discount for all orders
# Remove this when proper discount system is implemented
total *= 0.95
order['total'] = total
return order
def calculate_shipping(weight, distance):
"""
Calculate shipping cost based on weight and distance.
Last updated: 2025-06-20
Rate changes: Updated base rate from $5 to $7 per zone
"""
# Base shipping rates (updated 2025-06-20)
base_rate = 7.00 # Was $5.00, increased due to fuel costs
per_pound_rate = 0.50
per_mile_rate = 0.02
# Calculate total shipping cost
weight_cost = weight * per_pound_rate
distance_cost = distance * per_mile_rate
total_shipping = base_rate + weight_cost + distance_cost
return round(total_shipping, 2)
class BankAccount:
"""Represents a bank account with basic operations."""
def __init__(self, account_holder, initial_balance=0):
"""
Initialize a new bank account.
Args:
account_holder (str): Name of the account holder
initial_balance (float): Starting balance (default: 0)
"""
self.account_holder = account_holder
self.balance = initial_balance
self.transaction_history = []
# Record initial deposit if any
if initial_balance > 0:
self._record_transaction("Initial Deposit", initial_balance)
def deposit(self, amount):
"""
Deposit money into the account.
Args:
amount (float): Amount to deposit (must be positive)
Raises:
ValueError: If amount is not positive
"""
if amount <= 0:
raise ValueError("Deposit amount must be positive")
self.balance += amount
self._record_transaction("Deposit", amount)
return self.balance
def withdraw(self, amount):
"""
Withdraw money from the account.
Args:
amount (float): Amount to withdraw (must be positive)
Returns:
float: New balance after withdrawal
Raises:
ValueError: If amount is not positive
InsufficientFundsError: If insufficient balance
"""
if amount <= 0:
raise ValueError("Withdrawal amount must be positive")
if amount > self.balance:
raise ValueError("Insufficient funds")
self.balance -= amount
self._record_transaction("Withdrawal", -amount)
return self.balance
def _record_transaction(self, transaction_type, amount):
"""Private method to record transaction history."""
import datetime
transaction = {
'type': transaction_type,
'amount': amount,
'timestamp': datetime.datetime.now(),
'balance_after': self.balance
}
self.transaction_history.append(transaction)
def get_statement(self):
"""Generate account statement with transaction history."""
statement = f"Account Statement for {self.account_holder}\n"
statement += f"Current Balance: ${self.balance:.2f}\n\n"
statement += "Transaction History:\n"
statement += "-" * 50 + "\n"
for transaction in self.transaction_history:
date_str = transaction['timestamp'].strftime("%Y-%m-%d %H:%M")
statement += f"{date_str} | {transaction['type']} | "
statement += f"${abs(transaction['amount']):.2f} | "
statement += f"Balance: ${transaction['balance_after']:.2f}\n"
return statement
Good comments and readable code are essential for maintainable programs:
Comment Best Practices:
- Explain WHY, not just WHAT
- Document complex algorithms and business logic
- Use docstrings for functions and classes
- Keep comments up-to-date with code changes
- Avoid obvious comments that state what the code clearly shows
Code Readability Tips:
- Use descriptive variable and function names
- Break complex expressions into smaller, named parts
- Group related code together with whitespace
- Follow consistent formatting and indentation
- Write self-documenting code that minimizes need for comments
Documentation Strategy:
- Write docstrings for all public functions and classes
- Include examples in docstrings when helpful
- Document assumptions, limitations, and edge cases
- Use TODO and FIXME comments for future improvements
- Maintain comments when code changes
Remember: Code is written once but read many times. Invest in making it clear and well-documented for future maintainers (including yourself)!