Prerequisites
- Basic understanding of programming concepts ๐
- Python installation (3.8+) ๐
- VS Code or preferred IDE ๐ป
What you'll learn
- Understand the concept fundamentals ๐ฏ
- Apply the concept in real projects ๐๏ธ
- Debug common issues ๐
- Write clean, Pythonic code โจ
๐ฏ Introduction
Welcome to this exciting tutorial on Python code style and auto-formatting! ๐ In this guide, weโll explore how PEP 8 and auto-formatting tools can transform your Python development experience.
Youโll discover how consistent code style makes your Python code more readable, maintainable, and professional. Whether youโre building web applications ๐, data science projects ๐, or automation scripts ๐ค, understanding code style standards is essential for writing clean, Pythonic code that others (and future you!) will love to work with.
By the end of this tutorial, youโll be writing beautifully formatted Python code that follows industry standards! Letโs dive in! ๐โโ๏ธ
๐ Understanding PEP 8 and Code Style
๐ค What is PEP 8?
PEP 8 is like the fashion guide for Python code ๐. Think of it as the style manual that helps all Python developers write code that looks consistent and professional, just like how a dress code ensures everyone at a fancy restaurant looks presentable! ๐ฝ๏ธ
In Python terms, PEP 8 is the official style guide that defines conventions for writing readable Python code. This means you can:
- โจ Write code that any Python developer can easily understand
- ๐ Collaborate seamlessly with teams worldwide
- ๐ก๏ธ Reduce bugs by following proven patterns
๐ก Why Use PEP 8 and Auto-formatting?
Hereโs why developers love consistent code style:
- Readability ๐: Code is read more often than itโs written
- Team Collaboration ๐ฅ: Everyone follows the same rules
- Reduced Cognitive Load ๐ง : Focus on logic, not formatting
- Professional Standards ๐ผ: Industry-wide best practices
Real-world example: Imagine joining a new team ๐ฅ. With PEP 8, you can immediately understand their code without deciphering personal coding styles!
๐ง Basic Syntax and Usage
๐ PEP 8 Basics
Letโs start with essential PEP 8 rules:
# ๐ Hello, PEP 8!
# โ
Correct: Use 4 spaces for indentation (not tabs!)
def greet_python():
message = "Welcome to clean Python code! ๐"
print(message)
# ๐จ Naming conventions
class ShoppingCart: # Classes: PascalCase
def add_item(self): # Functions/methods: snake_case
MAX_ITEMS = 100 # Constants: UPPER_SNAKE_CASE
item_count = 0 # Variables: snake_case
๐ก Explanation: Notice how consistent naming makes code predictable and easy to read!
๐ฏ Common PEP 8 Patterns
Here are patterns youโll use daily:
# ๐๏ธ Import organization
import os
import sys
from datetime import datetime
import numpy as np
import pandas as pd
from my_module import helper_function
# ๐จ Line length (max 79 characters)
# โ
Good: Break long lines
long_string = (
"This is a very long string that would exceed "
"79 characters if written on one line"
)
# ๐ Spacing around operators
# โ
Correct spacing
x = 5
y = x * 2 + 1
result = calculate_score(x, y)
# โ Wrong: No spaces
x=5
y=x*2+1
๐ก Practical Examples
๐ Example 1: E-commerce Price Calculator
Letโs build something real with proper style:
# ๐๏ธ PEP 8 compliant price calculator
class PriceCalculator:
"""Calculate prices with discounts and taxes."""
TAX_RATE = 0.08 # 8% sales tax
def __init__(self):
self.items = []
self.discount_codes = {
"SAVE10": 0.10, # 10% off
"WELCOME": 0.15, # 15% off for new customers
"SUMMER": 0.20 # 20% summer sale
}
def add_item(self, name, price, quantity=1):
"""Add item to cart with proper validation."""
if price < 0:
raise ValueError("Price cannot be negative! ๐ฐ")
item = {
"name": name,
"price": price,
"quantity": quantity,
"emoji": self._get_item_emoji(name)
}
self.items.append(item)
print(f"Added {item['emoji']} {name} to cart!")
def calculate_total(self, discount_code=None):
"""Calculate total with optional discount."""
subtotal = sum(
item["price"] * item["quantity"]
for item in self.items
)
# Apply discount if valid
if discount_code and discount_code in self.discount_codes:
discount = self.discount_codes[discount_code]
subtotal *= (1 - discount)
print(f"๐ Discount applied: {discount * 100:.0f}% off!")
# Add tax
tax = subtotal * self.TAX_RATE
total = subtotal + tax
return {
"subtotal": round(subtotal, 2),
"tax": round(tax, 2),
"total": round(total, 2)
}
def _get_item_emoji(self, name):
"""Get emoji based on item name."""
emoji_map = {
"book": "๐",
"coffee": "โ",
"laptop": "๐ป",
"pizza": "๐"
}
for key, emoji in emoji_map.items():
if key in name.lower():
return emoji
return "๐ฆ" # Default package emoji
# ๐ฎ Let's use it!
cart = PriceCalculator()
cart.add_item("Python Book", 29.99)
cart.add_item("Coffee Mug", 12.99, quantity=2)
total_info = cart.calculate_total("SAVE10")
print(f"๐ฐ Total: ${total_info['total']}")
๐ฏ Try it yourself: Add a method to remove items and list all items in the cart!
๐ฎ Example 2: Game Score Formatter
Letโs format game scores with style:
# ๐ Well-formatted score tracking system
from datetime import datetime
from typing import List, Dict, Optional
class GameScoreFormatter:
"""Format and display game scores following PEP 8."""
HIGH_SCORE_THRESHOLD = 1000
ACHIEVEMENT_EMOJIS = {
"first_win": "๐",
"streak": "๐ฅ",
"high_score": "๐",
"perfect": "๐ฏ"
}
def __init__(self, game_name: str):
self.game_name = game_name
self.scores: List[Dict] = []
def add_score(self, player_name: str, score: int,
time_played: int) -> None:
"""Add a new score with timestamp."""
score_entry = {
"player": player_name,
"score": score,
"time_played": time_played, # in seconds
"timestamp": datetime.now(),
"achievements": self._check_achievements(score, time_played)
}
self.scores.append(score_entry)
self._display_score_entry(score_entry)
def _check_achievements(self, score: int,
time_played: int) -> List[str]:
"""Check which achievements were earned."""
achievements = []
if score >= self.HIGH_SCORE_THRESHOLD:
achievements.append("high_score")
if score == 1000 and time_played < 60:
achievements.append("perfect")
if len(self.scores) == 0:
achievements.append("first_win")
return achievements
def _display_score_entry(self, entry: Dict) -> None:
"""Display formatted score entry."""
print(f"\n๐ฎ {self.game_name} - New Score!")
print(f"๐ค Player: {entry['player']}")
print(f"๐ฏ Score: {entry['score']:,} points")
print(f"โฑ๏ธ Time: {entry['time_played']} seconds")
if entry['achievements']:
print("๐ Achievements unlocked:")
for achievement in entry['achievements']:
emoji = self.ACHIEVEMENT_EMOJIS.get(achievement, "โญ")
formatted_name = achievement.replace("_", " ").title()
print(f" {emoji} {formatted_name}")
def get_leaderboard(self, top_n: int = 5) -> List[Dict]:
"""Get top N scores, properly formatted."""
sorted_scores = sorted(
self.scores,
key=lambda x: x['score'],
reverse=True
)
return sorted_scores[:top_n]
def display_leaderboard(self) -> None:
"""Display formatted leaderboard."""
leaderboard = self.get_leaderboard()
print(f"\n๐ {self.game_name} Leaderboard ๐")
print("=" * 40)
for index, entry in enumerate(leaderboard, 1):
medal = self._get_medal_emoji(index)
print(
f"{medal} {index}. {entry['player']:<15} "
f"{entry['score']:>6,} pts"
)
@staticmethod
def _get_medal_emoji(position: int) -> str:
"""Get medal emoji for position."""
medals = {1: "๐ฅ", 2: "๐ฅ", 3: "๐ฅ"}
return medals.get(position, "๐
")
# ๐ฎ Let's play!
game = GameScoreFormatter("Python Quest")
game.add_score("Alice", 1200, 45)
game.add_score("Bob", 950, 62)
game.add_score("Charlie", 1000, 58)
game.display_leaderboard()
๐ Advanced Concepts
๐งโโ๏ธ Auto-formatting Tools
When youโre ready to level up, use auto-formatting tools:
# ๐ฏ Popular Python formatters
# 1. Black - The uncompromising formatter
# Install: pip install black
# Usage: black your_file.py
# 2. autopep8 - PEP 8 compliance tool
# Install: pip install autopep8
# Usage: autopep8 --in-place your_file.py
# 3. isort - Import statement sorter
# Install: pip install isort
# Usage: isort your_file.py
# ๐ช Example: Before formatting
def calculate_discount(price,discount_percent,minimum_price=10):
if price<minimum_price:return 0
return price*discount_percent/100
# โจ After Black formatting
def calculate_discount(price, discount_percent, minimum_price=10):
if price < minimum_price:
return 0
return price * discount_percent / 100
# ๐ง Configuration example (pyproject.toml)
"""
[tool.black]
line-length = 88
target-version = ['py38']
include = '\.pyi?$'
[tool.isort]
profile = "black"
line_length = 88
"""
๐๏ธ Type Hints and Documentation
For the brave developers, combine PEP 8 with type hints:
# ๐ Advanced PEP 8 with type hints
from typing import List, Dict, Optional, Union
from dataclasses import dataclass
from enum import Enum
class ItemCategory(Enum):
"""Categories for inventory items."""
ELECTRONICS = "electronics"
BOOKS = "books"
CLOTHING = "clothing"
FOOD = "food"
@dataclass
class InventoryItem:
"""Represent an item in inventory."""
name: str
category: ItemCategory
price: float
quantity: int
emoji: str = "๐ฆ"
def __post_init__(self) -> None:
"""Validate item after initialization."""
if self.price < 0:
raise ValueError("Price cannot be negative!")
if self.quantity < 0:
raise ValueError("Quantity cannot be negative!")
@property
def total_value(self) -> float:
"""Calculate total value of items in stock."""
return self.price * self.quantity
def apply_discount(self, percent: float) -> float:
"""Apply discount and return new price."""
if not 0 <= percent <= 100:
raise ValueError("Discount must be between 0 and 100!")
discount_amount = self.price * (percent / 100)
return round(self.price - discount_amount, 2)
class InventoryManager:
"""Manage inventory with PEP 8 compliance."""
def __init__(self) -> None:
self.items: Dict[str, InventoryItem] = {}
def add_item(self, item: InventoryItem) -> None:
"""Add item to inventory."""
self.items[item.name] = item
print(f"โ
Added {item.emoji} {item.name} to inventory!")
def get_category_report(self) -> Dict[ItemCategory, float]:
"""Generate value report by category."""
report: Dict[ItemCategory, float] = {}
for item in self.items.values():
if item.category not in report:
report[item.category] = 0
report[item.category] += item.total_value
return report
def find_items_by_price_range(
self,
min_price: float,
max_price: float
) -> List[InventoryItem]:
"""Find items within price range."""
return [
item for item in self.items.values()
if min_price <= item.price <= max_price
]
โ ๏ธ Common Pitfalls and Solutions
๐ฑ Pitfall 1: Inconsistent Indentation
# โ Wrong way - mixed tabs and spaces!
def calculate_total(items):
total = 0
for item in items:
total += item.price # This line uses a tab!
return total
# โ
Correct way - consistent 4 spaces
def calculate_total(items):
total = 0
for item in items:
total += item.price # 4 spaces everywhere
return total
๐คฏ Pitfall 2: Line Length Violations
# โ Dangerous - line too long!
def send_notification(user_email, subject, message, attachments=None, cc_list=None, priority="normal"):
print(f"Sending email to {user_email} with subject '{subject}' and message '{message}' with priority {priority}")
# โ
Safe - properly formatted!
def send_notification(
user_email,
subject,
message,
attachments=None,
cc_list=None,
priority="normal"
):
print(
f"Sending email to {user_email} with subject '{subject}' "
f"and message '{message}' with priority {priority}"
)
๐ ๏ธ Best Practices
- ๐ฏ Use Auto-formatters: Let tools handle formatting automatically!
- ๐ Configure Your Editor: Set up automatic PEP 8 checking
- ๐ก๏ธ Pre-commit Hooks: Format code before committing
- ๐จ Be Consistent: Pick a style and stick to it
- โจ Document Your Choices: If you deviate from PEP 8, document why
๐งช Hands-On Exercise
๐ฏ Challenge: Create a PEP 8 Compliant Recipe Manager
Create a recipe management system following PEP 8:
๐ Requirements:
- โ Recipe class with ingredients and instructions
- ๐ท๏ธ Categories (breakfast, lunch, dinner, dessert)
- ๐ค Chef attribution with ratings
- ๐ Preparation and cooking times
- ๐จ Each recipe needs an emoji!
๐ Bonus Points:
- Add search by ingredient
- Calculate total calories
- Generate shopping list from multiple recipes
๐ก Solution
๐ Click to see solution
# ๐ฏ PEP 8 compliant recipe manager!
from typing import List, Dict, Optional
from datetime import datetime
from enum import Enum
class RecipeCategory(Enum):
"""Recipe categories with emojis."""
BREAKFAST = ("breakfast", "๐
")
LUNCH = ("lunch", "โ๏ธ")
DINNER = ("dinner", "๐")
DESSERT = ("dessert", "๐ฐ")
def __init__(self, value: str, emoji: str):
self._value_ = value
self.emoji = emoji
class Recipe:
"""A cooking recipe following PEP 8 standards."""
def __init__(
self,
name: str,
category: RecipeCategory,
ingredients: Dict[str, str],
instructions: List[str],
prep_time: int, # minutes
cook_time: int, # minutes
chef: str,
emoji: str = "๐ฝ๏ธ"
):
self.name = name
self.category = category
self.ingredients = ingredients
self.instructions = instructions
self.prep_time = prep_time
self.cook_time = cook_time
self.chef = chef
self.emoji = emoji
self.ratings: List[int] = []
self.created_at = datetime.now()
@property
def total_time(self) -> int:
"""Calculate total cooking time."""
return self.prep_time + self.cook_time
@property
def average_rating(self) -> float:
"""Calculate average rating."""
if not self.ratings:
return 0.0
return sum(self.ratings) / len(self.ratings)
def add_rating(self, rating: int) -> None:
"""Add a rating (1-5 stars)."""
if not 1 <= rating <= 5:
raise ValueError("Rating must be between 1 and 5! โญ")
self.ratings.append(rating)
print(f"โ
Added {rating}โญ rating to {self.name}!")
def display_recipe(self) -> None:
"""Display recipe in formatted style."""
print(f"\n{self.emoji} {self.name}")
print(f"๐จโ๐ณ Chef: {self.chef}")
print(f"๐ Rating: {self.average_rating:.1f}โญ")
print(f"โฑ๏ธ Time: {self.total_time} minutes")
print(f"๐ท๏ธ Category: {self.category.emoji} {self.category.value}")
print("\n๐ Ingredients:")
for ingredient, amount in self.ingredients.items():
print(f" โข {ingredient}: {amount}")
print("\n๐จโ๐ณ Instructions:")
for i, instruction in enumerate(self.instructions, 1):
print(f" {i}. {instruction}")
class RecipeManager:
"""Manage recipes with PEP 8 compliance."""
def __init__(self):
self.recipes: Dict[str, Recipe] = {}
def add_recipe(self, recipe: Recipe) -> None:
"""Add a new recipe."""
self.recipes[recipe.name] = recipe
print(
f"โ
Added {recipe.emoji} {recipe.name} "
f"to your cookbook!"
)
def search_by_ingredient(self, ingredient: str) -> List[Recipe]:
"""Find recipes containing an ingredient."""
matching_recipes = []
for recipe in self.recipes.values():
if any(ingredient.lower() in ing.lower()
for ing in recipe.ingredients):
matching_recipes.append(recipe)
return matching_recipes
def get_shopping_list(
self,
recipe_names: List[str]
) -> Dict[str, List[str]]:
"""Generate shopping list from multiple recipes."""
shopping_list: Dict[str, List[str]] = {}
for name in recipe_names:
if name not in self.recipes:
continue
recipe = self.recipes[name]
for ingredient, amount in recipe.ingredients.items():
if ingredient not in shopping_list:
shopping_list[ingredient] = []
shopping_list[ingredient].append(
f"{amount} (for {recipe.name})"
)
return shopping_list
def display_by_category(self, category: RecipeCategory) -> None:
"""Display all recipes in a category."""
recipes_in_category = [
r for r in self.recipes.values()
if r.category == category
]
if not recipes_in_category:
print(f"No {category.value} recipes found! ๐")
return
print(f"\n{category.emoji} {category.value.title()} Recipes:")
for recipe in recipes_in_category:
rating_stars = "โญ" * int(recipe.average_rating)
print(
f" {recipe.emoji} {recipe.name} "
f"({recipe.total_time} min) {rating_stars}"
)
# ๐ฎ Test it out!
cookbook = RecipeManager()
# Add a breakfast recipe
pancakes = Recipe(
name="Fluffy Pancakes",
category=RecipeCategory.BREAKFAST,
ingredients={
"flour": "2 cups",
"milk": "1.5 cups",
"eggs": "2",
"sugar": "2 tbsp",
"baking powder": "2 tsp"
},
instructions=[
"Mix dry ingredients in a bowl",
"Whisk wet ingredients separately",
"Combine and mix until just blended",
"Cook on griddle until bubbles form",
"Flip and cook until golden brown"
],
prep_time=10,
cook_time=15,
chef="Chef Emma",
emoji="๐ฅ"
)
cookbook.add_recipe(pancakes)
pancakes.add_rating(5)
pancakes.display_recipe()
๐ Key Takeaways
Youโve learned so much! Hereโs what you can now do:
- โ Write PEP 8 compliant code with confidence ๐ช
- โ Use auto-formatting tools to save time ๐ก๏ธ
- โ Create readable, professional Python code ๐ฏ
- โ Collaborate better with consistent style ๐ค
- โ Debug faster with clean, organized code! ๐
Remember: Consistent style isnโt about being perfectโitโs about making your code a joy to work with! ๐ค
๐ค Next Steps
Congratulations! ๐ Youโve mastered Python code style and auto-formatting!
Hereโs what to do next:
- ๐ป Install Black or autopep8 and try them on your code
- ๐๏ธ Configure your editor with PEP 8 checking
- ๐ Move on to our next tutorial: Type Annotations Basics
- ๐ Share your beautifully formatted code with others!
Remember: Clean code is a gift to your future self and your teammates. Keep formatting, keep learning, and most importantly, have fun! ๐
Happy coding! ๐๐โจ