""" ================================================================================ File: 01_pep8.py Topic: PEP 8 - Python Style Guide ================================================================================ This file demonstrates PEP 8, the official Python style guide. Following PEP 8 makes your code more readable, consistent, and professional. These are conventions, not strict rules, but following them is highly recommended. Key Concepts: - Indentation and whitespace - Naming conventions - Line length and wrapping - Imports organization - Comments and docstrings Reference: https://peps.python.org/pep-0008/ ================================================================================ """ # ============================================================================= # 1. INDENTATION # ============================================================================= # Use 4 spaces per indentation level. Never mix tabs and spaces. # GOOD def function_with_proper_indentation(): if True: for i in range(10): print(i) # Aligned with opening delimiter foo = long_function_name(var_one, var_two, var_three, var_four) # Hanging indent (add a level) def long_function_name( var_one, var_two, var_three, var_four): print(var_one) # ============================================================================= # 2. LINE LENGTH # ============================================================================= # Limit lines to 79 characters (72 for docstrings/comments) # GOOD - Use implicit line continuation total = (first_variable + second_variable + third_variable) # GOOD - Use backslash when necessary with open('/very/long/path/to/file.txt') as file_one, \ open('/another/long/path/to/file.txt') as file_two: pass # ============================================================================= # 3. BLANK LINES # ============================================================================= # - 2 blank lines around top-level functions and classes # - 1 blank line between methods in a class class FirstClass: """First class.""" pass class SecondClass: """Second class.""" def method_one(self): """First method.""" pass def method_two(self): """Second method.""" pass def top_level_function(): """A top-level function.""" pass # ============================================================================= # 4. IMPORTS # ============================================================================= # - One import per line # - Group in order: standard library, third-party, local # - Use absolute imports # GOOD import os import sys from typing import List, Optional # Third party imports (after blank line) # import numpy as np # import pandas as pd # Local imports (after blank line) # from mypackage import mymodule # BAD - Multiple imports on one line # import os, sys # ============================================================================= # 5. WHITESPACE # ============================================================================= # GOOD - No extra whitespace inside brackets spam = [1, 2, 3] ham = {"key": "value"} eggs = (1,) # BAD # spam = [ 1, 2, 3 ] # ham = { 'key': 'value' } # GOOD - One space around operators x = 1 y = 2 z = x + y # BAD - No space around = in keyword arguments # def function(x, y = 5): def function(x, y=5): pass # GOOD - Space after comma some_list = [1, 2, 3] # GOOD - No space before colon in slices some_list[1:3] some_list[::2] # ============================================================================= # 6. NAMING CONVENTIONS # ============================================================================= # Variables and functions: lowercase_with_underscores (snake_case) user_name = "John" total_count = 42 def calculate_average(numbers): return sum(numbers) / len(numbers) # Constants: UPPERCASE_WITH_UNDERSCORES MAX_BUFFER_SIZE = 4096 DEFAULT_TIMEOUT = 30 PI = 3.14159 # Classes: CapitalizedWords (PascalCase) class UserAccount: pass class HttpConnection: pass # Private: prefix with underscore _internal_variable = "private" def _internal_function(): pass class MyClass: def _protected_method(self): """Single underscore = protected (convention).""" pass def __private_method(self): """Double underscore = name mangling (truly private).""" pass # ============================================================================= # 7. COMMENTS # ============================================================================= # GOOD - Inline comments have at least 2 spaces before # x = 5 # This is an inline comment # Block comments precede the code they describe # This is a block comment that explains # the following piece of code. complex_calculation = 1 + 2 + 3 # Don't state the obvious # BAD: x = 5 # Assign 5 to x # GOOD: x = 5 # Default timeout in seconds # ============================================================================= # 8. DOCSTRINGS # ============================================================================= def example_function(param1, param2): """ Brief description of the function. Longer description if needed. Explain what the function does, not how it does it. Args: param1: Description of first parameter param2: Description of second parameter Returns: Description of what is returned Raises: ValueError: When param1 is negative Example: >>> example_function(1, 2) 3 """ return param1 + param2 class ExampleClass: """Brief description of the class. Longer description of the class including its purpose and usage patterns. Attributes: attr1: Description of first attribute attr2: Description of second attribute """ def __init__(self, attr1, attr2): """Initialize ExampleClass.""" self.attr1 = attr1 self.attr2 = attr2 # ============================================================================= # 9. COMPARISON AND BOOLEAN # ============================================================================= # Use 'is' and 'is not' for None comparisons # GOOD x = None if x is None: pass # BAD # if x == None: # Use 'is not' instead of 'not ... is' # GOOD if x is not None: pass # BAD # if not x is None: # Don't compare boolean values with == or != # GOOD flag = True if flag: pass # BAD # if flag == True: # if flag is True: # Only use when testing identity # ============================================================================= # 10. EXCEPTION HANDLING # ============================================================================= # Catch specific exceptions # GOOD try: value = int(user_input) except ValueError: print("Invalid input") # BAD - Too broad # try: # value = int(user_input) # except: # or except Exception: # print("Error") # Use 'raise' to re-raise exception try: process_data() except ValueError: logger.error("Bad value") raise # ============================================================================= # 11. FUNCTION ANNOTATIONS (Type Hints) # ============================================================================= def greeting(name: str) -> str: """Return a greeting.""" return f"Hello, {name}!" # Complex types from typing import List, Dict, Optional def process_items( items: List[str], config: Dict[str, int], default: Optional[str] = None ) -> bool: """Process items with configuration.""" return True # ============================================================================= # 12. SUMMARY: KEY RULES # ============================================================================= print("PEP 8 Summary - Key Rules:") print(""" 1. Use 4 spaces for indentation 2. Limit lines to 79 characters 3. Use blank lines to separate functions and classes 4. Organize imports: standard lib, third-party, local 5. Use snake_case for functions and variables 6. Use PascalCase for classes 7. Use UPPER_CASE for constants 8. Use spaces around operators and after commas 9. Write docstrings for all public modules, functions, classes 10. Compare with 'is' for None, use bool directly """) # Use flake8 or black to automatically check/format code print("Tools to help with PEP 8:") print(" - flake8: Check for PEP 8 violations") print(" - black: Automatic code formatting") print(" - isort: Sort imports automatically") print(" - pylint: Comprehensive code analysis")