Ei vielä käännetty
Tätä sivua ei ole vielä käännetty suomeksi, joten se näytetään englanniksi. Auta kääntämään
abc Module Complexity¶
The abc module provides infrastructure for defining abstract base classes (ABCs) in Python, enforcing that derived classes implement specified methods.
Complexity Reference¶
| Operation | Time | Space | Notes |
|---|---|---|---|
@abstractmethod decorator |
O(1) | O(1) | Mark method abstract |
@abstractclassmethod decorator |
O(1) | O(1) | Mark classmethod abstract (legacy helper) |
@abstractstaticmethod decorator |
O(1) | O(1) | Mark staticmethod abstract (legacy helper) |
@abstractproperty decorator |
O(1) | O(1) | Mark property abstract (legacy helper) |
| Class instantiation attempt | O(n) | O(n) | n = abstract methods |
isinstance(obj, ABC) |
O(n) | O(1) | n = MRO length; may also check virtual subclasses |
issubclass(cls, ABC) |
O(n) | O(1) | n = MRO length; may also check virtual subclasses |
| Method resolution (MRO) | O(n) | O(n) | n = class hierarchy depth |
| Register virtual subclass | O(1) | O(n) | n = registered classes |
get_cache_token() |
O(1) | O(1) | Monotonic token for ABC cache invalidation |
update_abstractmethods(cls) |
O(n) | O(n) | n = class hierarchy depth |
Abstract Base Classes¶
Basic Abstract Class¶
from abc import ABC, abstractmethod
# Define abstract base class - O(1)
class Animal(ABC):
# Mark as abstract - O(1)
@abstractmethod
def make_sound(self):
"""Subclasses must implement this"""
pass
# Concrete method in ABC - O(1)
def sleep(self):
return "Zzz..."
# Attempt instantiation - O(n) check for abstract methods
try:
animal = Animal() # TypeError
except TypeError as e:
print("Cannot instantiate ABC")
# Concrete subclass - O(1)
class Dog(Animal):
def make_sound(self):
return "Woof!"
# Can instantiate concrete class - O(n)
dog = Dog()
print(dog.make_sound()) # Woof!
Abstract Properties¶
from abc import ABC, abstractmethod
class Shape(ABC):
# Abstract property - O(1)
@property
@abstractmethod
def area(self):
pass
@property
@abstractmethod
def perimeter(self):
pass
# Concrete implementation - O(1)
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
return self.width * self.height
@property
def perimeter(self):
return 2 * (self.width + self.height)
# Create instance - O(n)
rect = Rectangle(5, 3)
# Access properties - O(1)
print(rect.area) # 15
print(rect.perimeter) # 16
Abstract Class Methods¶
from abc import ABC, abstractmethod
class DatabaseConnection(ABC):
# Abstract class method - O(1)
@classmethod
@abstractmethod
def from_config(cls, config):
pass
class PostgresConnection(DatabaseConnection):
@classmethod
def from_config(cls, config):
return cls(config['host'], config['port'])
# Use class method - O(1)
conn = PostgresConnection.from_config({'host': 'localhost', 'port': 5432})
Abstract Static Methods¶
from abc import ABC, abstractmethod
class Validator(ABC):
# Abstract static method - O(1)
@staticmethod
@abstractmethod
def validate(value):
pass
class EmailValidator(Validator):
@staticmethod
def validate(value):
return '@' in value
# Use static method - O(1)
is_valid = EmailValidator.validate("user@example.com")
Multiple Abstract Methods¶
Enforcing Multiple Implementations¶
from abc import ABC, abstractmethod
class DataStore(ABC):
# Multiple abstract methods - O(n) to enforce
@abstractmethod
def read(self, key):
pass
@abstractmethod
def write(self, key, value):
pass
@abstractmethod
def delete(self, key):
pass
# Incomplete implementation - TypeError
class PartialStore(DataStore):
def read(self, key):
return None
# Missing write() and delete()
try:
store = PartialStore() # O(n) - checks all 3 methods
except TypeError:
print("Must implement all abstract methods")
# Complete implementation - O(1)
class MemoryStore(DataStore):
def __init__(self):
self.data = {}
def read(self, key):
return self.data.get(key)
def write(self, key, value):
self.data[key] = value
def delete(self, key):
del self.data[key]
# Create instance - O(n)
store = MemoryStore()
Virtual Subclasses¶
Register Virtual Subclass¶
from abc import ABC, abstractmethod
class PluginInterface(ABC):
@abstractmethod
def execute(self):
pass
# Existing class not inheriting from ABC
class LegacyPlugin:
def execute(self):
return "Legacy execution"
# Register as virtual subclass - O(1) per registration
PluginInterface.register(LegacyPlugin)
# Check relationship - O(n) against inheritance chain
obj = LegacyPlugin()
print(isinstance(obj, PluginInterface)) # True
print(issubclass(LegacyPlugin, PluginInterface)) # True
Virtual Subclass Benefits¶
from abc import ABC, abstractmethod
class Drawable(ABC):
@abstractmethod
def draw(self):
pass
# Register multiple unrelated classes
class Circle:
def draw(self):
return "Drawing circle..."
class Rectangle:
def draw(self):
return "Drawing rectangle..."
# Register both - O(1) each
Drawable.register(Circle)
Drawable.register(Rectangle)
# Polymorphic usage - O(n) per check
def render(obj):
if isinstance(obj, Drawable):
return obj.draw()
return "Not drawable"
# Works without inheritance
circle = Circle()
print(render(circle)) # Drawing circle...
Inheritance Hierarchies¶
Multi-Level Inheritance¶
from abc import ABC, abstractmethod
# Level 1 - Abstract base
class Vehicle(ABC):
@abstractmethod
def start(self):
pass
# Level 2 - Intermediate abstract
class Car(Vehicle):
@abstractmethod
def open_trunk(self):
pass
# Level 3 - Concrete implementation
class Sedan(Car):
def start(self):
return "Engine running"
def open_trunk(self):
return "Trunk opened"
# Create instance - O(n) checks hierarchy
sedan = Sedan()
print(sedan.start()) # Engine running
print(sedan.open_trunk()) # Trunk opened
Mixin with Abstract Base¶
from abc import ABC, abstractmethod
class Logger:
"""Mixin - not abstract"""
def log(self, message):
return f"LOG: {message}"
class Serializable(ABC):
"""Abstract mixin"""
@abstractmethod
def to_dict(self):
pass
class User(Logger, Serializable):
def __init__(self, name, email):
self.name = name
self.email = email
def to_dict(self):
return {'name': self.name, 'email': self.email}
# Create instance - O(n)
user = User("Alice", "alice@example.com")
# Use mixin methods - O(1)
print(user.log("User created")) # LOG: User created
print(user.to_dict()) # {'name': 'Alice', ...}
Common Patterns¶
Factory Pattern with ABC¶
from abc import ABC, abstractmethod
class Driver(ABC):
@abstractmethod
def connect(self):
pass
class PostgresDriver(Driver):
def connect(self):
return "Connected to PostgreSQL"
class MySQLDriver(Driver):
def connect(self):
return "Connected to MySQL"
class DriverFactory:
# O(1) factory lookup
@staticmethod
def create_driver(db_type):
drivers = {
'postgres': PostgresDriver,
'mysql': MySQLDriver
}
driver_class = drivers.get(db_type)
if driver_class:
return driver_class()
raise ValueError(f"Unknown driver: {db_type}")
# Use factory - O(1)
driver = DriverFactory.create_driver('postgres')
print(driver.connect()) # Connected to PostgreSQL
Template Method Pattern¶
from abc import ABC, abstractmethod
class DataProcessor(ABC):
# Template method - defines algorithm structure
def process(self, data):
validated = self.validate(data) # O(?)
transformed = self.transform(validated) # O(?)
return self.save(transformed) # O(?)
@abstractmethod
def validate(self, data):
pass
@abstractmethod
def transform(self, data):
pass
@abstractmethod
def save(self, data):
pass
class CSVProcessor(DataProcessor):
def validate(self, data):
return len(data) > 0
def transform(self, data):
return data.upper()
def save(self, data):
return f"Saved CSV: {data}"
# Use - O(?) based on implementation
processor = CSVProcessor()
result = processor.process("csv data")
Checking Implementation¶
Verification Methods¶
from abc import ABC, abstractmethod
class Interface(ABC):
@abstractmethod
def required_method(self):
pass
class Implementation(Interface):
def required_method(self):
return "Implemented"
# Check if subclass - O(n)
print(issubclass(Implementation, Interface)) # True
# Check if instance - O(n)
obj = Implementation()
print(isinstance(obj, Interface)) # True
# Check abstract methods - O(n) to compute set
abstract_methods = Interface.__abstractmethods__
print(abstract_methods) # frozenset({'required_method'})
Performance Considerations¶
Instantiation Cost¶
from abc import ABC, abstractmethod
import time
class AbstractBase(ABC):
@abstractmethod
def method(self):
pass
class Concrete(AbstractBase):
def method(self):
return None
# Instantiation checks abstracts - O(n)
start = time.time()
for _ in range(100000):
obj = Concrete()
elapsed = time.time() - start
# Cost is O(1) per instance, n checks at class definition time
Virtual Subclass Lookups¶
from abc import ABC
class MyABC(ABC):
pass
# Register many - O(k) total for k registrations
for i in range(1000):
class DummyClass:
pass
MyABC.register(DummyClass)
# isinstance checks - O(n) in worst case
class TestClass:
pass
MyABC.register(TestClass)
# Check - O(n) through registered classes
result = isinstance(TestClass(), MyABC)
Best Practices¶
Do's¶
- Use ABC for interface definition
- Clearly document abstract methods
- Use
@abstractmethodconsistently - Provide concrete implementations in subclasses
from abc import ABC, abstractmethod
class Cache(ABC):
"""Cache interface for different backends"""
@abstractmethod
def get(self, key):
"""Retrieve value by key"""
pass
@abstractmethod
def set(self, key, value):
"""Store key-value pair"""
pass
Avoid's¶
- Don't create ABCs for single-use classes
- Don't use virtual registration excessively
- Don't override abstract methods to remove implementation
- Don't use ABC when simple inheritance suffices