mirror of
https://github.com/blshaer/python-by-example.git
synced 2026-03-27 23:29:25 +01:00
335 lines
8.5 KiB
Python
335 lines
8.5 KiB
Python
"""
|
|
================================================================================
|
|
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")
|