@abstractmethod and Enforcement Rules
Pyyhkäise näyttääksesi valikon
@abstractmethod is the decorator that marks a method as required. It has specific rules about how it interacts with other decorators, what happens when subclasses override it, and what counts as a valid implementation.
The Basic Contract
A method decorated with @abstractmethod must be overridden in every concrete subclass. The ABC itself can provide a body – but the body is never called automatically. It serves as a default implementation that subclasses can explicitly invoke with super():
12345678910111213141516171819202122from abc import ABC, abstractmethod class Validator(ABC): @abstractmethod def validate(self, value): # Default logic subclasses can call via super() if value is None: raise ValueError("Value cannot be None") class RangeValidator(Validator): def __init__(self, min_val, max_val): self.min_val = min_val self.max_val = max_val def validate(self, value): super().validate(value) # Calling the abstract method's body if not (self.min_val <= value <= self.max_val): raise ValueError(f"{value} is outside [{self.min_val}, {self.max_val}]") validator = RangeValidator(0, 100) validator.validate(50) # Passes validator.validate(None) # Raises ValueError from super()
Combining @abstractmethod with Other Decorators
@abstractmethod must always be the innermost decorator – closest to the function definition. Placing it on the outside breaks enforcement:
123456789101112131415161718192021222324252627282930313233343536from abc import ABC, abstractmethod class DataSource(ABC): # Correct: @abstractmethod is innermost @property @abstractmethod def connection_string(self): pass # Correct: @abstractmethod is innermost @classmethod @abstractmethod def from_config(cls, config): pass # Correct: @abstractmethod is innermost @staticmethod @abstractmethod def validate_schema(schema): pass class PostgresSource(DataSource): @property def connection_string(self): return "postgresql://localhost:5432/db" @classmethod def from_config(cls, config): return cls() @staticmethod def validate_schema(schema): return isinstance(schema, dict) source = PostgresSource() print(source.connection_string)
Overriding Does Not Require Calling super()
A concrete implementation simply needs to exist – calling super() is optional:
12345678910111213141516171819202122from abc import ABC, abstractmethod class Serializer(ABC): @abstractmethod def serialize(self, data): pass @abstractmethod def deserialize(self, raw): pass class JsonSerializer(Serializer): def serialize(self, data): import json return json.dumps(data) # No super() call required def deserialize(self, raw): import json return json.loads(raw) serializer = JsonSerializer() print(serializer.serialize({"amount": 4500.0, "currency": "USD"}))
What Does Not Count as an Implementation
Defining a method with only pass or only ... in the subclass does satisfy the requirement – the override exists even if it does nothing:
12345678910111213from abc import ABC, abstractmethod class Notifier(ABC): @abstractmethod def send(self, message): pass class SilentNotifier(Notifier): def send(self, message): pass # Valid – override exists, does nothing notifier = SilentNotifier() # No TypeError notifier.send("alert") # Does nothing, no error
The enforcement is syntactic – Python checks that the name exists in the subclass's __dict__ or its MRO, not that it does meaningful work.
Kiitos palautteestasi!
Kysy tekoälyä
Kysy tekoälyä
Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme