Back to topics
Chapter 01 — Overview

@staticmethod vs @abstractmethod

Two decorators that look similar but serve completely different purposes in Python.

What You'll Learn

Python has several method decorators that change how methods behave inside classes. Two of the most important — and most confused — are @abstractmethod and @staticmethod.

@abstractmethod

Enforce that subclasses implement required methods. Comes from the abc module. Design pattern enforcement.

@staticmethod

A utility function inside a class that doesn't need self. Built-in Python — no import needed.

Key Distinction @abstractmethod says: "You MUST implement this in your subclass." @staticmethod says: "This function doesn't need an instance to run."
Chapter 02 — Fundamentals

@abstractmethod — Enforce Subclass Implementation

Force every subclass to implement specific methods. The foundation of plugin and agent architectures.

python
from abc import ABC, abstractmethod

class Agent(ABC):  # MUST inherit from ABC
    @abstractmethod
    def run(self, query: str) -> str:
        """Subclass MUST implement this."""
        pass

# ❌ Can't instantiate abstract class
agent = Agent()
# TypeError: Can't instantiate abstract class Agent with abstract method run

# ✅ Subclass MUST implement it
class ResearchAgent(Agent):
    def run(self, query: str) -> str:
        return "research results"

agent = ResearchAgent()  # Works!

Purpose: Enforce that subclasses implement required methods. This is design pattern enforcement — the base class defines what must exist, subclasses define how it works.

⚠️ Requires ABC The class must inherit from ABC (Abstract Base Class). Without it, @abstractmethod won't enforce anything — Python will happily let you instantiate the class with an empty method.
Chapter 03 — Fundamentals

@staticmethod — Method Without self

A utility function that lives inside a class for organization — no instance state needed.

python
class Utils:  # NO ABC needed
    @staticmethod
    def validate_email(email: str) -> bool:
        """No self parameter! Just a function in a class."""
        return "@" in email and "." in email

# ✅ Call on class itself (no instance needed)
is_valid = Utils.validate_email("amir@example.com")  # True

# ✅ Also works on instance (but doesn't use it)
utils = Utils()
is_valid = utils.validate_email("amir@example.com")  # Also works

Purpose: Organize utility functions inside a class without needing an instance. No self, no instance state — just a function grouped with related logic.

💡 When to use Use @staticmethod when the method doesn't access self (instance) or cls (class). It's purely organizational — the function could live outside the class, but grouping it inside makes your code more readable.
Chapter 04 — Comparison

Side-by-Side Comparison with Code

See exactly how each decorator works in a real architecture.

@abstractmethod: Enforce Architecture

python
from abc import ABC, abstractmethod

class DataBackend(ABC):
    """All storage backends MUST implement these."""

    @abstractmethod
    def save(self, key: str, value: str):
        """Subclass MUST implement."""
        pass

    @abstractmethod
    def load(self, key: str) -> str:
        """Subclass MUST implement."""
        pass

# ✅ Complete implementation
class RedisBackend(DataBackend):
    def save(self, key: str, value: str):
        redis.set(key, value)  # Uses self (instance)

    def load(self, key: str) -> str:
        return redis.get(key)  # Uses self (instance)

backend = RedisBackend()  # Works!

# ❌ Incomplete implementation
class MemoryBackend(DataBackend):
    def save(self, key: str, value: str):
        self.data[key] = value
    # Forgot load()!

backend = MemoryBackend()
# TypeError: Can't instantiate MemoryBackend with abstract method load

Key point: save() and load() need self because they interact with instance state (redis connection, self.data, etc).

@staticmethod: Utility Functions

python
class InputValidator:
    """Helper functions, no state needed."""

    @staticmethod
    def validate_query(query: str) -> bool:
        """Pure utility. No self needed."""
        return len(query) > 0 and len(query) < 2000

    @staticmethod
    def sanitize_log_data(data: dict) -> dict:
        """No instance state. Just helper logic."""
        return {k: "***" if k in ["password", "token"] else v
                for k, v in data.items()}

    @staticmethod
    def extract_text_content(content) -> str:
        """No instance needed. Pure transformation."""
        if isinstance(content, str):
            return content
        if isinstance(content, list):
            return " ".join(str(item) for item in content)
        return str(content)

# Use directly on class (no instance needed)
is_valid = InputValidator.validate_query("test query")  # True
clean_data = InputValidator.sanitize_log_data({"password": "secret"})
# {'password': '***'}

Key point: These methods don't need instance state. They're just utility functions grouped in a class for organization.

Chapter 05 — Reference

Import Sources — Where Do They Come From?

Only abstractmethod is in abc. The rest are built-in.

⚠️ Common Mistake "Do all of them come from abc?" — NO! Only abstractmethod is in abc. @staticmethod is a Python built-in — no import needed.
python
# ✅ abstractmethod comes from abc module
from abc import ABC, abstractmethod

# ✅ staticmethod is BUILT-IN (no import needed)
class MyClass:
    @staticmethod
    def helper():
        pass

# ❌ This is WRONG
from abc import staticmethod  # ERROR! staticmethod not in abc module

Complete Import Map

DecoratorModuleImport
@abstractmethodabcfrom abc import abstractmethod
@staticmethodBuilt-inNo import needed
@classmethodBuilt-inNo import needed
@propertyBuilt-inNo import needed
Chapter 06 — Reference

All Built-in Python Decorators

The four decorators every Python developer should know cold.

1. @staticmethod — No self, no cls

python
class Math:
    @staticmethod
    def add(a, b):
        return a + b

Math.add(1, 2)  # 3 (no instance needed)

2. @classmethod — Has cls, not self

python
class Config:
    default_value = "test"

    @classmethod
    def get_default(cls):
        return cls.default_value  # cls is the class itself

Config.get_default()  # "test"

3. @property — Access attribute like a method

python
class User:
    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

user = User("Amir")
user.name  # "Amir" (looks like attribute, but computed)

4. @abstractmethod (from abc module)

python
from abc import ABC, abstractmethod

class BaseClass(ABC):
    @abstractmethod
    def method(self):
        pass

Quick Comparison

DecoratorFirst paramNeeds import?Purpose
@staticmethodNoneNoUtility function in a class
@classmethodclsNoAccess class-level attributes
@propertyselfNoComputed attribute access
@abstractmethodselfYes (abc)Force subclass implementation
Chapter 07 — Applied

Real-World Example: BaseAgent

See both decorators working together in a production agent architecture.

python
from abc import ABC, abstractmethod
import logging
import time

class BaseAgent(ABC):
    def __init__(self, name: str):
        self.name = name
        self._log = logging.getLogger(f"{__name__}.{name}")
        self._start_time = time.monotonic()

    # ✅ abstractmethod — Forces all agents to implement
    @abstractmethod
    def build_graph(self) -> Any:
        """Must be implemented by subclasses."""
        pass

    @abstractmethod
    def run(self, query: str) -> str:
        """Must be implemented by subclasses."""
        pass

    # ✅ Static method — Utility function, no instance needed
    @staticmethod
    def extract_text_content(content: Any) -> str:
        """Pure utility. Doesn't need self."""
        if isinstance(content, str):
            return content
        if isinstance(content, list):
            return " ".join(str(item) for item in content)
        return str(content)

    # Regular instance method — Uses self
    def elapsed_seconds(self) -> float:
        """Uses self._start_time from instance."""
        return time.monotonic() - self._start_time

Usage Patterns

python
# ✅ Call static method on class (no instance)
text = BaseAgent.extract_text_content(["hello", "world"])

# ✅ Call static method on instance (still no self)
agent = ResearchAgent(name="researcher")
text = agent.extract_text_content(["hello"])

# ✅ Call instance method (needs instance)
elapsed = agent.elapsed_seconds()  # Uses agent._start_time

# ❌ Can't instantiate abstract class
agent = BaseAgent()  # ERROR (has abstract methods)
🔑 Three method types in one class build_graph() and run() are abstract — every agent must implement them differently. extract_text_content() is static — shared utility, same for all agents. elapsed_seconds() is a regular method — needs self to access instance state.
Chapter 08 — Cheat Sheet

Summary & Cheat Sheet

Everything on one page — the definitive reference.

Full Comparison Table

Feature@abstractmethod@staticmethod
Import sourcefrom abc import abstractmethodBuilt-in (no import)
Requires ABC parentYESNO
Has self parameterYES (enforced)NO (explicitly not)
Can instantiate classNO (if abstract methods exist)YES (always)
PurposeEnforce subclass implementationOrganize utility functions
When to useDesign patterns, architectureHelpers, validators, parsers
Examplerun() in agentsvalidate_email() in validators

The Two-Line Summary

@abstractmethod (from abc)

"This method MUST be implemented by subclasses"

@staticmethod (built-in)

"This is a utility function, no instance needed"

Decision Flowchart

Does the method need access to self (instance)? ├── YES → Regular instance method └── NO → Does it need access to cls (class)? ├── YES → @classmethod └── NO → Is it a contract for subclasses? ├── YES → @abstractmethod (from abc) └── NO → @staticmethod (built-in)
🎓 You've Completed the Guide! You now understand the difference between @abstractmethod (enforces architecture) and @staticmethod (organizes utilities), where each comes from, and how they work together in real-world agent patterns.