How to Implement a Factory Method by Type String in Python
A factory method maps a type string to a class, creating and returning the appropriate object instance while handling unknown types gracefully.
Python code
36 linesclass Animal:
def speak(self):
raise NotImplementedError
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
class AnimalFactory:
@staticmethod
def create(animal_type: str) -> Animal:
animal_types = {
"dog": Dog,
"cat": Cat
}
animal_class = animal_types.get(animal_type.lower())
if animal_class is None:
raise ValueError(f"Unknown animal type: {animal_type}")
return animal_class()
if __name__ == "__main__":
factory = AnimalFactory()
for animal in ["dog", "cat", "bird"]:
try:
instance = factory.create(animal)
print(f"{animal}: {instance.speak()}")
except ValueError as e:
print(f"{animal}: {e}")
Output
dog: Woof!
cat: Meow!
bird: Unknown animal type: bird
How it works
This factory pattern centralizes object creation by mapping type strings to classes in a dictionary. The AnimalFactory.create static method looks up the class based on the lowercase type string, raises a ValueError for unknown types, and returns a new instance. This approach decouples client code from concrete classes, making the system easier to extend with new types without modifying callers. The use of static methods avoids needing an instance of the factory itself.
Common mistakes
- Forgetting to handle case sensitivity when matching type strings
- Not raising a clear error for unknown types, leading to silent failures
- Using if/else chains instead of a dictionary for maintainability
Variations
- Use a registry decorator to auto-register classes as they are defined
- Implement the factory as a classmethod and use subclasses of the factory for different groups
Real-world use cases
- Parsing user input in a CLI tool to instantiate different command handlers.
- Selecting a payment provider class based on a configuration string in an e-commerce backend.
- Creating database connection objects for different database types in a data pipeline.
Sponsored
More from System design patterns
- Build a BFF (Backend for Frontend) Mock Aggregator in Python medium
- Builder pattern for mocking complex objects in Python easy
- Circuit Breaker Pattern in Python: Closed, Open, and Half-Open States medium
- Create a Data Helper Class in Python easy
- Domain Driven Design Aggregate Root Example in Python medium
- Facade Pattern in Python with Mock Simplification medium
Keep learning
Related tutorials and quizzes for this topic.