Writing Code the Python Way
What is "Pythonic" Code?
You can solve any problem in many ways. But Python has a preferred style — clean, readable, and elegant. Code written this way is called Pythonic.
Two programmers can solve the same problem:
# Non-Pythonic — works but ugly
numbers = [1, 2, 3, 4, 5]
squares = []
for i in range(len(numbers)):
squares.append(numbers[i] ** 2)
# Pythonic — clean and elegant
squares = [n ** 2 for n in numbers]
Same result. But the second version is shorter, more readable, and more Python-like.
This stage teaches you to write code like an experienced Python developer.
Part 1 — List Comprehensions
The Problem
This pattern appears everywhere:
# Create a new list by transforming another list
result = []
for item in original_list:
result.append(transform(item))
It works but it's 3 lines every time. List comprehension does it in 1.
Basic List Comprehension
# Syntax
new_list = [expression for item in iterable]
Examples:
# Squares of numbers
numbers = [1, 2, 3, 4, 5]
# Old way
squares = []
for n in numbers:
squares.append(n ** 2)
# List comprehension
squares = [n ** 2 for n in numbers]
print(squares) # [1, 4, 9, 16, 25]
# Uppercase all strings
fruits = ["apple", "banana", "mango"]
upper_fruits = [f.upper() for f in fruits]
print(upper_fruits) # ['APPLE', 'BANANA', 'MANGO']
# Get lengths of words
words = ["Python", "is", "awesome"]
lengths = [len(w) for w in words]
print(lengths) # [6, 2, 7]
List Comprehension with Condition
# Syntax
new_list = [expression for item in iterable if condition]
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Only even numbers
evens = [n for n in numbers if n % 2 == 0]
print(evens) # [2, 4, 6, 8, 10]
# Only numbers greater than 5
big = [n for n in numbers if n > 5]
print(big) # [6, 7, 8, 9, 10]
# Squares of only even numbers
even_squares = [n ** 2 for n in numbers if n % 2 == 0]
print(even_squares) # [4, 16, 36, 64, 100]
Dictionary Comprehension
Same concept for dictionaries:
# Syntax
new_dict = {key: value for item in iterable}
# Square of each number as dict
numbers = [1, 2, 3, 4, 5]
squares_dict = {n: n ** 2 for n in numbers}
print(squares_dict) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Flip keys and values
original = {"name": "Gagan", "age": 22, "city": "Delhi"}
flipped = {value: key for key, value in original.items()}
print(flipped) # {'Gagan': 'name', 22: 'age', 'Delhi': 'city'}
# Filter a dictionary
marks = {"Rahul": 85, "Priya": 92, "Gagan": 45, "Amit": 78, "Neha": 38}
passed = {name: mark for name, mark in marks.items() if mark >= 50}
print(passed) # {'Rahul': 85, 'Priya': 92, 'Amit': 78}
Set Comprehension
numbers = [1, 2, 2, 3, 3, 3, 4]
unique_squares = {n ** 2 for n in numbers}
print(unique_squares) # {1, 4, 9, 16} — unique values only
When NOT to Use Comprehensions
Comprehensions are great but don't overuse them:
# Too complex — hard to read
result = [x ** 2 for x in range(20) if x % 2 == 0 if x % 3 == 0]
# Better as a regular loop with clear logic
result = []
for x in range(20):
if x % 2 == 0 and x % 3 == 0:
result.append(x ** 2)
Rule — if comprehension is hard to read in one glance, use a regular loop.
Part 2 — Lambda Functions
What is a Lambda?
A lambda is a small anonymous function — a function without a name, written in one line.
# Regular function
def square(n):
return n ** 2
# Lambda equivalent
square = lambda n: n ** 2
print(square(5)) # 25
Syntax:
lambda parameters: expression
Why Lambda?
Lambdas are not meant to replace regular functions. They're useful when you need a small throwaway function in one place — especially with sorted(), map(), filter().
Lambda with sorted()
students = [
{"name": "Rahul", "marks": 85},
{"name": "Priya", "marks": 92},
{"name": "Gagan", "marks": 78},
{"name": "Amit", "marks": 95}
]
# Sort by marks
sorted_students = sorted(students, key=lambda s: s["marks"])
for s in sorted_students:
print(f"{s['name']}: {s['marks']}")
Output:
Gagan: 78
Rahul: 85
Priya: 92
Amit: 95
# Sort by name
sorted_by_name = sorted(students, key=lambda s: s["name"])
# Sort by marks descending
sorted_desc = sorted(students, key=lambda s: s["marks"], reverse=True)
map() — Apply Function to Every Item
numbers = [1, 2, 3, 4, 5]
# Apply function to each item
squares = list(map(lambda n: n ** 2, numbers))
print(squares) # [1, 4, 9, 16, 25]
# Same as list comprehension
squares = [n ** 2 for n in numbers]
# Convert all strings to uppercase
names = ["rahul", "priya", "gagan"]
upper = list(map(lambda n: n.upper(), names))
print(upper) # ['RAHUL', 'PRIYA', 'GAGAN']
filter() — Filter Items by Condition
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Keep only even numbers
evens = list(filter(lambda n: n % 2 == 0, numbers))
print(evens) # [2, 4, 6, 8, 10]
# Keep only passing marks
marks = [85, 42, 90, 38, 75, 55, 29]
passed = list(filter(lambda m: m >= 50, marks))
print(passed) # [85, 90, 75, 55]
Part 3 — Useful Pythonic Patterns
Unpacking
# Basic unpacking
a, b, c = [1, 2, 3]
print(a, b, c) # 1 2 3
# Swap variables — Pythonic way
x, y = 10, 20
x, y = y, x # swap in one line
print(x, y) # 20 10
# Extended unpacking
first, *rest = [1, 2, 3, 4, 5]
print(first) # 1
print(rest) # [2, 3, 4, 5]
*beginning, last = [1, 2, 3, 4, 5]
print(beginning) # [1, 2, 3, 4]
print(last) # 5
Enumerate — Already Seen, Important Enough to Revisit
fruits = ["apple", "banana", "mango"]
# Non-Pythonic
for i in range(len(fruits)):
print(f"{i + 1}. {fruits[i]}")
# Pythonic
for i, fruit in enumerate(fruits, start=1):
print(f"{i}. {fruit}")
Output:
1. apple
2. banana
3. mango
1. apple
2. banana
3. mango
zip — Combine Two Lists
names = ["Rahul", "Priya", "Gagan"]
marks = [85, 92, 78]
for name, mark in zip(names, marks):
print(f"{name}: {mark}")
Output:
Rahul: 85
Priya: 92
Gagan: 78
# Create dictionary from two lists
students_dict = dict(zip(names, marks))
print(students_dict) # {'Rahul': 85, 'Priya': 92, 'Gagan': 78}
any() and all()
marks = [85, 92, 78, 45, 90]
# all() — True if ALL items satisfy condition
all_passed = all(m >= 50 for m in marks)
print(all_passed) # False — 45 fails
# any() — True if AT LEAST ONE item satisfies condition
anyone_failed = any(m < 50 for m in marks)
print(anyone_failed) # True — 45 fails
# Practical example
passwords = ["abc", "password123", "xyz"]
has_strong = any(len(p) >= 8 for p in passwords)
print(has_strong) # True — password123 is long enough
Ternary Operator — One Line If/Else
# Regular if/else
age = 20
if age >= 18:
status = "Adult"
else:
status = "Minor"
# Ternary — one line
status = "Adult" if age >= 18 else "Minor"
print(status) # Adult
# In f-strings
age = 20
print(f"You are {'Adult' if age >= 18 else 'Minor'}")
_ as Throwaway Variable
When you don't need a variable:
# You need the index but not the value
for _ in range(5):
print("Hello") # print 5 times, don't need loop variable
# Unpacking but only want some values
name, _, city = ("Gagan", 22, "Delhi") # ignore age
print(name, city) # Gagan Delhi
Part 4 — Code Quality
Meaningful Names
# Bad names
x = 86400
def calc(a, b):
return a * b / 100
# Good names
SECONDS_IN_DAY = 86400
def calculate_percentage(score, total):
return score * total / 100
Constants in UPPER_CASE
# Constants — values that never change
MAX_RETRIES = 3
DEFAULT_TIMEOUT = 30
DATABASE_URL = "postgresql://localhost/mydb"
PI = 3.14159
Functions Should Do One Thing
# Bad — function doing too much
def process_student(name, marks):
average = sum(marks) / len(marks)
if average >= 90: grade = "A"
elif average >= 80: grade = "B"
else: grade = "C"
print(f"Name: {name}")
print(f"Average: {average}")
print(f"Grade: {grade}")
with open("results.txt", "a") as f:
f.write(f"{name},{average},{grade}\n")
# Good — each function does one thing
def calculate_average(marks):
return sum(marks) / len(marks)
def get_grade(average):
if average >= 90: return "A"
elif average >= 80: return "B"
else: return "C"
def print_result(name, average, grade):
print(f"Name: {name}, Average: {average}, Grade: {grade}")
def save_result(name, average, grade):
with open("results.txt", "a") as f:
f.write(f"{name},{average},{grade}\n")
Docstrings — Document Your Code
def calculate_average(marks):
"""
Calculate the average of a list of marks.
Args:
marks (list): List of numerical marks
Returns:
float: The average mark
Example:
>>> calculate_average([85, 90, 78])
84.33
"""
if not marks:
return 0
return sum(marks) / len(marks)
Docstrings appear when someone calls help(calculate_average). Professional code always has docstrings.
PEP 8 — Python Style Guide
PEP 8 is the official Python style guide. Key rules:
# Indentation — 4 spaces (not tabs)
def my_function():
x = 10
return x
# Spaces around operators
x = 5 + 3 # correct
x=5+3 # wrong
# No space before colon in dict/slice
d = {"key": "value"} # correct
d = {"key" : "value"} # wrong
# Two blank lines between top-level functions/classes
def function_one():
pass
def function_two():
pass
class MyClass:
pass
# One blank line between methods inside class
class MyClass:
def method_one(self):
pass
def method_two(self):
pass
# Max line length — 79 characters
# Long lines — use backslash or parentheses
result = (value_one + value_two +
value_three + value_four)
# Imports — one per line, at the top
import os
import json
from datetime import datetime
Final Real World Example — Everything Together
A clean, Pythonic, well-structured program:
"""
expense_tracker.py
A simple expense tracker using Pythonic best practices.
"""
import json
import os
from datetime import datetime
EXPENSES_FILE = "expenses.json"
CATEGORIES = ["food", "transport", "shopping", "bills", "entertainment", "other"]
def load_expenses():
"""Load expenses from JSON file."""
if not os.path.exists(EXPENSES_FILE):
return []
with open(EXPENSES_FILE, "r") as file:
return json.load(file)
def save_expenses(expenses):
"""Save expenses to JSON file."""
with open(EXPENSES_FILE, "w") as file:
json.dump(expenses, file, indent=4)
def add_expense(expenses):
"""Add a new expense entry."""
print("\nCategories:", ", ".join(CATEGORIES))
description = input("Description: ").strip()
category = input("Category: ").strip().lower()
if category not in CATEGORIES:
print(f"Invalid category. Using 'other'")
category = "other"
try:
amount = float(input("Amount (Rs.): "))
if amount <= 0:
print("Amount must be positive")
return
except ValueError:
print("Invalid amount")
return
expense = {
"id": len(expenses) + 1,
"description": description,
"category": category,
"amount": amount,
"date": datetime.now().strftime("%Y-%m-%d")
}
expenses.append(expense)
save_expenses(expenses)
print(f"Expense added: Rs.{amount:.2f} for {description}")
def view_expenses(expenses):
"""Display all expenses."""
if not expenses:
print("No expenses recorded yet")
return
print(f"\n{'ID':<5} {'Date':<12} {'Category':<15} {'Amount':<12} {'Description'}")
print("-" * 60)
for e in expenses:
print(f"{e['id']:<5} {e['date']:<12} {e['category']:<15} Rs.{e['amount']:<10.2f} {e['description']}")
total = sum(e["amount"] for e in expenses)
print("-" * 60)
print(f"{'Total:':<33} Rs.{total:.2f}")
def view_by_category(expenses):
"""Show expense summary by category."""
if not expenses:
print("No expenses recorded yet")
return
category_totals = {}
for e in expenses:
cat = e["category"]
category_totals[cat] = category_totals.get(cat, 0) + e["amount"]
print("\n=== Expenses by Category ===")
sorted_cats = sorted(category_totals.items(), key=lambda x: x[1], reverse=True)
for category, total in sorted_cats:
print(f" {category:<15}: Rs.{total:.2f}")
def filter_by_category(expenses):
"""Filter expenses by category."""
category = input("Enter category: ").strip().lower()
filtered = [e for e in expenses if e["category"] == category]
if not filtered:
print(f"No expenses in category '{category}'")
return
print(f"\n=== {category.title()} Expenses ===")
for e in filtered:
print(f" {e['date']} — Rs.{e['amount']:.2f} — {e['description']}")
total = sum(e["amount"] for e in filtered)
print(f" Total: Rs.{total:.2f}")
def main():
"""Main program loop."""
expenses = load_expenses()
print(f"Loaded {len(expenses)} existing expenses")
menu_options = {
"1": ("Add expense", add_expense),
"2": ("View all expenses", view_expenses),
"3": ("View by category", view_by_category),
"4": ("Filter by category", filter_by_category),
"5": ("Exit", None)
}
while True:
print("\n=== Expense Tracker ===")
for key, (label, _) in menu_options.items():
print(f"{key}. {label}")
choice = input("Choice: ").strip()
if choice == "5":
print("Goodbye!")
break
elif choice in menu_options:
_, func = menu_options[choice]
func(expenses)
else:
print("Invalid choice")
if __name__ == "__main__":
main()
Notice what's Pythonic here:
- Docstrings on every function
- List comprehension for filtering
sum() with generator expression
sorted() with lambda
- Dictionary for menu options
.get() for safe dictionary access
if __name__ == "__main__" — standard entry point
if __name__ == "__main__" — Explained
def main():
print("Program running")
if __name__ == "__main__":
main()
When Python runs a file directly — __name__ equals "__main__" so main() runs.
When another file imports this file — __name__ equals the filename so main() does NOT run automatically.
This is standard in every professional Python script. Always write it.
Exercise 🏋️ — Final Project
You've completed all 10 stages. Now build a complete CLI application combining everything:
Personal Finance Manager:
=== Personal Finance Manager ===
1. Add income
2. Add expense
3. View transactions
4. View balance
5. Monthly summary
6. Export to file
7. Exit
Requirements:
- OOP —
Transaction class, Account class
- File handling — save/load from JSON
- Error handling — all inputs validated
- Modules — datetime, json, os
- Pythonic code — comprehensions, clean functions, docstrings
- Categories for both income and expenses
- Monthly summary showing income vs expense vs savings
This is your capstone project — it combines every single concept from all 10 stages. Take your time, build it properly.
🎉 Congratulations — You've Completed the Roadmap!
Let's look at everything you've learned:
|
Stage
|
Topics
|
|
Stage 1
|
Setup,
print, variables, data types, math, input
|
|
Stage 2
|
If/else, elif, loops, break,
continue
|
|
Stage 3
|
Functions,
parameters, return, scope
|
|
Stage 4
|
Lists, tuples, dictionaries,
sets
|
|
Stage 5
|
String
methods, formatting, f-strings
|
|
Stage 6
|
File read/write, CSV, JSON
files
|
|
Stage 7
|
Try/except,
error types, raising exceptions
|
|
Stage 8
|
Built-in modules, pip,
external libraries
|
|
Stage 9
|
Classes,
objects, inheritance, polymorphism
|
|
Stage 10
|
Comprehensions, lambda,
Pythonic patterns
|
What's Next After Core Python?
Now that you know Core Python — pick a direction:
Web Development:
- Flask or Django framework
- Build websites and APIs
Data Science / AI:
- NumPy, Pandas, Matplotlib
- Machine Learning with scikit-learn
Automation:
- Selenium — automate browsers
- PyAutoGUI — automate desktop
- Schedule — run tasks automatically
Backend Development:
- FastAPI — modern API framework
- PostgreSQL with psycopg2
- REST API development