Course Topics
Introduction Python Overview Setting Up Python Python Syntax Basics First Steps with Python Comparing Python with Other Languages Basics Variables and Data Types Input and Output Type Conversion Comments and Code Readability Naming Conventions Control Flow Conditional Statements Loops in Python Loop Control Mechanisms Nested Control Structures Data Structures Working with Strings Lists Tuples Sets Dictionaries Comprehensions Iterators and Generators Functions Defining and Calling Functions Function Arguments and Parameters Lambda Functions Return Values Recursion Variable Scope in Functions Modules and Packages Importing Modules Built-in Modules Creating Custom Modules Working with Packages Virtual Environments Managing Packages with pip Object-Oriented Programming Classes and Objects Attributes and Methods Constructors and Initializers Inheritance and Polymorphism Encapsulation and Abstraction Class Methods and Static Methods Using super() and Method Resolution File Handling Reading and Writing Text Files File Modes and File Pointers Using Context Managers (with) Working with CSV Files Handling JSON Data Error Handling Types of Errors and Exceptions Try, Except, Finally Blocks Raising Exceptions Built-in vs Custom Exceptions Exception Handling Best Practices Advanced Python Decorators Advanced Generators Context Managers Functional Programming Tools Coroutines and Async Programming Introduction to Metaclasses Memory Management in Python Useful Libraries Math Module Random Module Date and Time Handling Regular Expressions (re) File and OS Operations (os, sys, shutil) Data Structures Enhancements (collections, itertools) Web APIs (requests) Data Analysis Libraries (NumPy, Pandas) Visualization Tools (matplotlib) Database Access SQLite in Python Connecting to MySQL/PostgreSQL Executing SQL Queries Using ORMs (SQLAlchemy Intro) Transactions and Error Handling Web Development Introduction to Web Frameworks Flask Basics (Routing, Templates) Django Overview Handling Forms and Requests Creating REST APIs Working with JSON and HTTP Methods Testing and Debugging Debugging Techniques Using assert and Logging Writing Unit Tests (unittest) Introduction to pytest Handling and Fixing Common Bugs Automation and Scripting Automating File Operations Web Scraping with BeautifulSoup Automating Excel Tasks (openpyxl) Sending Emails with Python Task Scheduling and Timers System Automation with subprocess

Naming Conventions

Why Naming Conventions Matter

Naming conventions are standardized rules for naming variables, functions, classes, and other elements in your code. Good naming makes your code more readable, maintainable, and professional. It's like having a consistent style guide that helps everyone understand your code quickly.

Python follows the PEP 8 style guide, which provides official recommendations for how to name different elements in Python code.

example:

# Poor naming
x = "John"
y = 25
z = x + " is " + str(y) + " years old"

# Good naming following conventions
user_name = "John"
user_age = 25
greeting_message = f"{user_name} is {user_age} years old"

Python Naming Styles

Python uses different naming styles for different types of identifiers:

snake_case (Recommended for most items)

# Variables
first_name = "Alice"
total_price = 199.99
is_logged_in = True

# Functions
def calculate_total_cost():
    pass

def send_email_notification():
    pass

# Module names
import user_authentication
import payment_processor

UPPER_CASE (Constants)

# Constants - values that never change
MAX_ATTEMPTS = 3
DEFAULT_TIMEOUT = 30
API_BASE_URL = "https://api.example.com"
PI = 3.14159

# Configuration values
DATABASE_HOST = "localhost"
DEFAULT_PAGE_SIZE = 20

PascalCase (Classes)

# Class names
class UserAccount:
    pass

class PaymentProcessor:
    pass

class EmailValidator:
    pass

class ShoppingCart:
    pass

mixedCase (Not typically used in Python)

# This style is common in other languages but NOT recommended in Python
# Avoid: firstName, lastName, calculateTotal
# Use instead: first_name, last_name, calculate_total

Variable Naming Best Practices

Use Descriptive Names

# Poor - unclear what these variables represent
a = 3.14159
b = 5
c = a * b * b

# Good - clear and descriptive
pi = 3.14159
radius = 5
circle_area = pi * radius * radius

# Even better - with proper context
PI = 3.14159  # Constant
circle_radius = 5  # meters
circle_area = PI * circle_radius ** 2

Avoid Abbreviations and Single Letters

# Poor abbreviations
usr_nm = "Sarah"
calc_tot = 150.75
temp_val = 42

# Better - full words
user_name = "Sarah"
calculated_total = 150.75
temperature_value = 42

# Exception: commonly understood abbreviations are okay
max_attempts = 3  # "max" is widely understood
min_password_length = 8  # "min" is acceptable
url = "https://example.com"  # "url" is standard

Use Meaningful Distinctions

# Poor - similar names that are confusing
user_data = {"name": "Tom", "age": 30}
user_info = {"email": "tom@email.com", "phone": "123-456-7890"}
user_details = {"address": "123 Main St", "city": "Boston"}

# Better - specific, meaningful names
user_profile = {"name": "Tom", "age": 30}
user_contact = {"email": "tom@email.com", "phone": "123-456-7890"}
user_address = {"street": "123 Main St", "city": "Boston"}

Boolean Variable Naming

# Use verbs or adjectives that clearly indicate true/false
is_valid = True
has_permission = False
can_edit = True
should_save = False
user_authenticated = True

# Avoid ambiguous boolean names
# Poor
flag = True  # What does this flag represent?
status = False  # What status?

# Good
is_file_uploaded = True
email_sent_successfully = False

Function Naming Conventions

Use Verbs for Actions

# Functions should describe what they do
def calculate_total_price(items):
    """Calculate the total price of items in cart."""
    return sum(item['price'] for item in items)

def validate_email_address(email):
    """Check if email address format is valid."""
    return '@' in email and '.' in email

def send_welcome_email(user_email):
    """Send welcome email to new user."""
    # Email sending logic here
    pass

def update_user_profile(user_id, new_data):
    """Update user profile with new information."""
    # Database update logic here
    pass

Specific Function Naming Patterns

# Getter functions - retrieve information
def get_user_by_id(user_id):
    """Retrieve user information by ID."""
    pass

def fetch_latest_orders():
    """Fetch the most recent orders from database."""
    pass

# Setter functions - modify information
def set_user_password(user_id, new_password):
    """Set new password for user."""
    pass

def update_inventory_count(item_id, new_count):
    """Update inventory count for specific item."""
    pass

# Boolean return functions - start with is_, has_, can_, should_
def is_user_admin(user_id):
    """Check if user has admin privileges."""
    return True  # Example return

def has_valid_subscription(user_id):
    """Check if user has active subscription."""
    return False  # Example return

def can_user_edit_post(user_id, post_id):
    """Check if user has permission to edit post."""
    return True  # Example return

Class Naming Conventions

Use Nouns in PascalCase

class User:
    """Represents a user in the system."""
    def __init__(self, name, email):
        self.name = name
        self.email = email

class ShoppingCart:
    """Manages items in a shopping cart."""
    def __init__(self):
        self.items = []

class EmailValidator:
    """Validates email addresses."""
    @staticmethod
    def is_valid(email):
        return '@' in email and '.' in email

class PaymentProcessor:
    """Handles payment processing operations."""
    def process_payment(self, amount, payment_method):
        # Payment processing logic
        pass

Class Member Naming

class BankAccount:
    """Represents a bank account."""

    # Class variables (shared by all instances)
    minimum_balance = 0  # snake_case
    ACCOUNT_TYPES = ['checking', 'savings', 'business']  # UPPER_CASE for constants

    def __init__(self, account_holder, initial_balance):
        # Public attributes (accessible from outside)
        self.account_holder = account_holder  # snake_case
        self.balance = initial_balance

        # Private attributes (internal use, start with underscore)
        self._account_number = self._generate_account_number()
        self._transaction_history = []

        # "Protected" attributes (convention, not enforced)
        self._creation_date = "2025-06-20"

    def deposit(self, amount):
        """Public method - snake_case."""
        if self._is_valid_amount(amount):
            self.balance += amount

    def _is_valid_amount(self, amount):
        """Private method - starts with underscore."""
        return amount > 0

    def _generate_account_number(self):
        """Private method for internal use."""
        import random
        return f"ACC{random.randint(10000, 99999)}"

Constants and Configuration

Naming Constants

# Application constants
APP_NAME = "Customer Management System"
VERSION = "1.2.3"
DEFAULT_LANGUAGE = "english"

# Mathematical constants
PI = 3.14159265359
SPEED_OF_LIGHT = 299792458  # meters per second
GOLDEN_RATIO = 1.618033988749

# Configuration settings
MAX_FILE_SIZE = 5242880  # 5MB in bytes
DEFAULT_TIMEOUT_SECONDS = 30
ALLOWED_FILE_TYPES = ['jpg', 'png', 'pdf', 'doc']

# Database configuration
DATABASE_HOST = "localhost"
DATABASE_PORT = 5432
MAX_CONNECTION_ATTEMPTS = 3

# API settings
API_BASE_URL = "https://api.example.com/v1"
REQUEST_TIMEOUT = 10
MAX_RETRIES = 3

Grouping Related Constants

# Option 1: Using a class as a namespace
class Colors:
    """Color constants for the application."""
    RED = "#FF0000"
    GREEN = "#00FF00"
    BLUE = "#0000FF"
    WHITE = "#FFFFFF"
    BLACK = "#000000"

class HttpStatus:
    """HTTP status code constants."""
    OK = 200
    NOT_FOUND = 404
    INTERNAL_ERROR = 500
    UNAUTHORIZED = 401

# Usage
background_color = Colors.WHITE
response_code = HttpStatus.OK

# Option 2: Using module-level constants with prefixes
COLOR_RED = "#FF0000"
COLOR_GREEN = "#00FF00"
COLOR_BLUE = "#0000FF"

HTTP_OK = 200
HTTP_NOT_FOUND = 404
HTTP_INTERNAL_ERROR = 500

File and Module Naming

Module Names

# Good module names (all lowercase, underscores if needed)
# user_authentication.py
# email_sender.py
# data_processor.py
# payment_utils.py

# Import examples
import user_authentication
import email_sender
from data_processor import clean_data
from payment_utils import calculate_tax

# Avoid
# UserAuthentication.py  # Don't use PascalCase for modules
# email-sender.py        # Don't use hyphens
# dataProcessor.py       # Don't use mixedCase

Package Structure Example

# Project structure with good naming
my_web_app/
    __init__.py
    main.py
    config.py
    models/
        __init__.py
        user_model.py
        product_model.py
    views/
        __init__.py
        user_views.py
        product_views.py
    utils/
        __init__.py
        email_utils.py
        validation_utils.py
        date_helpers.py

Naming in Different Contexts

Loop Variables and Iterators

# Simple loops - single letters are acceptable
for i in range(10):
    print(i)

# List iterations - use descriptive names
students = ["Alice", "Bob", "Charlie"]
for student in students:
    print(f"Hello, {student}")

# Dictionary iterations
user_scores = {"Alice": 95, "Bob": 87, "Charlie": 92}
for student_name, score in user_scores.items():
    print(f"{student_name}: {score}")

# Nested loops - be more descriptive
grade_matrix = [[85, 90, 78], [92, 88, 95], [79, 83, 91]]
for student_index, student_grades in enumerate(grade_matrix):
    for subject_index, grade in enumerate(student_grades):
        print(f"Student {student_index}, Subject {subject_index}: {grade}")

Exception Handling

# Exception variable naming
try:
    result = int(user_input)
except ValueError as conversion_error:
    print(f"Could not convert input: {conversion_error}")

try:
    file_content = open("data.txt").read()
except FileNotFoundError as file_error:
    print(f"File not found: {file_error}")
except PermissionError as permission_error:
    print(f"Permission denied: {permission_error}")

Temporary Variables

# Acceptable temporary variable names for short-lived variables
def process_data(data_list):
    # Temporary variables with clear context
    temp_total = 0
    temp_count = 0

    for item in data_list:
        temp_total += item['value']
        temp_count += 1

    average = temp_total / temp_count if temp_count > 0 else 0
    return average

# Even better - avoid temp variables when possible
def process_data_improved(data_list):
    if not data_list:
        return 0

    total_value = sum(item['value'] for item in data_list)
    item_count = len(data_list)
    return total_value / item_count

Common Naming Mistakes to Avoid

Misleading Names

# Misleading - this function doesn't just calculate, it also saves
def calculate_user_score(user_id, test_answers):
    score = evaluate_answers(test_answers)
    save_score_to_database(user_id, score)  # Unexpected side effect!
    return score

# Better - name reflects all actions
def calculate_and_save_user_score(user_id, test_answers):
    score = evaluate_answers(test_answers)
    save_score_to_database(user_id, score)
    return score

# Or separate the concerns
def calculate_user_score(test_answers):
    return evaluate_answers(test_answers)

def save_user_score(user_id, score):
    save_score_to_database(user_id, score)

Inconsistent Naming

# Inconsistent - mixing naming styles and terms
def getUserData(user_id):  # mixedCase (not Python style)
    pass

def get_user_info(user_id):  # snake_case
    pass

def fetchUserDetails(user_id):  # mixedCase + different verb
    pass

# Consistent - same style and pattern
def get_user_data(user_id):
    pass

def get_user_profile(user_id):
    pass

def get_user_preferences(user_id):
    pass

Using Reserved Words

# Avoid Python keywords and built-in function names
# Bad
list = [1, 2, 3]  # Shadows built-in list() function
str = "hello"     # Shadows built-in str() function
type = "user"     # Shadows built-in type() function

# Good
item_list = [1, 2, 3]
user_name = "hello"
user_type = "admin"

# If you must use a keyword-like name, add underscore
class_ = "Math101"  # Instead of using 'class'
from_ = "sender@email.com"  # Instead of using 'from'

Real-World Naming Example

E-commerce System

class Product:
    """Represents a product in the e-commerce system."""

    # Class constants
    PRODUCT_STATUSES = ['active', 'discontinued', 'out_of_stock']
    DEFAULT_CATEGORY = 'general'

    def __init__(self, product_name, product_price, category_name=None):
        # Public attributes
        self.product_name = product_name
        self.product_price = product_price
        self.category_name = category_name or self.DEFAULT_CATEGORY
        self.is_available = True

        # Private attributes
        self._product_id = self._generate_product_id()
        self._creation_timestamp = self._get_current_timestamp()

    def update_product_price(self, new_price):
        """Update the product price with validation."""
        if self._is_valid_price(new_price):
            old_price = self.product_price
            self.product_price = new_price
            self._log_price_change(old_price, new_price)
            return True
        return False

    def calculate_discounted_price(self, discount_percentage):
        """Calculate price after applying discount."""
        if not self._is_valid_discount(discount_percentage):
            raise ValueError("Invalid discount percentage")

        discount_amount = self.product_price * (discount_percentage / 100)
        discounted_price = self.product_price - discount_amount
        return round(discounted_price, 2)

    def _is_valid_price(self, price):
        """Private method to validate product price."""
        return isinstance(price, (int, float)) and price >= 0

    def _is_valid_discount(self, discount):
        """Private method to validate discount percentage."""
        return 0 <= discount <= 100

    def _generate_product_id(self):
        """Generate unique product ID."""
        import uuid
        return f"PROD_{uuid.uuid4().hex[:8].upper()}"

    def _get_current_timestamp(self):
        """Get current timestamp for record keeping."""
        import datetime
        return datetime.datetime.now()

    def _log_price_change(self, old_price, new_price):
        """Log price changes for audit trail."""
        print(f"Price changed: {old_price} -> {new_price}")

class ShoppingCart:
    """Manages items in a customer's shopping cart."""

    MAX_ITEMS_PER_CART = 50

    def __init__(self, customer_id):
        self.customer_id = customer_id
        self.cart_items = []
        self.total_amount = 0.0
        self.item_count = 0

    def add_product_to_cart(self, product, quantity=1):
        """Add product to cart with specified quantity."""
        if not self._can_add_items(quantity):
            raise ValueError(f"Cannot exceed {self.MAX_ITEMS_PER_CART} items")

        cart_item = {
            'product': product,
            'quantity': quantity,
            'item_total': product.product_price * quantity
        }

        self.cart_items.append(cart_item)
        self._update_cart_totals()

    def remove_product_from_cart(self, product_id):
        """Remove product from cart by product ID."""
        original_length = len(self.cart_items)
        self.cart_items = [
            item for item in self.cart_items 
            if item['product']._product_id != product_id
        ]

        if len(self.cart_items) < original_length:
            self._update_cart_totals()
            return True
        return False

    def calculate_cart_total(self):
        """Calculate total amount for all items in cart."""
        return sum(item['item_total'] for item in self.cart_items)

    def _can_add_items(self, quantity):
        """Check if items can be added without exceeding limit."""
        return self.item_count + quantity <= self.MAX_ITEMS_PER_CART

    def _update_cart_totals(self):
        """Update cart totals after modifications."""
        self.total_amount = self.calculate_cart_total()
        self.item_count = sum(item['quantity'] for item in self.cart_items)

# Usage example with good naming
def process_customer_order():
    """Process a customer order with proper naming throughout."""

    # Create products with descriptive names
    laptop_product = Product("Gaming Laptop", 1299.99, "Electronics")
    mouse_product = Product("Wireless Mouse", 49.99, "Electronics")

    # Create shopping cart
    customer_cart = ShoppingCart("CUST_12345")

    # Add products to cart
    customer_cart.add_product_to_cart(laptop_product, quantity=1)
    customer_cart.add_product_to_cart(mouse_product, quantity=2)

    # Calculate totals
    cart_total = customer_cart.calculate_cart_total()
    item_count = customer_cart.item_count

    print(f"Cart Total: ${cart_total:.2f}")
    print(f"Total Items: {item_count}")

Summary

Good naming conventions make your code more professional and maintainable:

Key Python Naming Rules:
- Variables and functions: snake_case
- Classes: PascalCase
- Constants: UPPER_CASE
- Private attributes: _leading_underscore
- Modules: lowercase_with_underscores

Best Practices:
- Use descriptive, meaningful names
- Be consistent throughout your codebase
- Avoid abbreviations and single letters (except for short loops)
- Use verbs for functions, nouns for classes
- Follow the single responsibility principle in naming
- Make boolean variables clearly indicate true/false

Remember:
- Code is read more often than it's written
- Good names reduce the need for comments
- Consistency is more important than personal preference
- Follow PEP 8 guidelines for Python-specific conventions

Investing time in good naming conventions will make your code more professional, readable, and maintainable for yourself and other developers!