Python Factory Method: Create Shapes by Type String
A factory method that maps a type string to a concrete shape class and returns an instance, with runtime error handling.
Python code
43 linesclass Shape:
def draw(self):
raise NotImplementedError
class Circle(Shape):
def draw(self):
return "Drawing a circle"
class Square(Shape):
def draw(self):
return "Drawing a square"
class Triangle(Shape):
def draw(self):
return "Drawing a triangle"
class ShapeFactory:
@staticmethod
def create(shape_type):
shape_type = shape_type.strip().lower()
shapes = {
"circle": Circle,
"square": Square,
"triangle": Triangle,
}
try:
return shapes[shape_type]()
except KeyError:
raise ValueError(f"Unknown shape type: {shape_type}")
if __name__ == "__main__":
factory = ShapeFactory()
for name in ["circle", "square", "triangle", "hexagon"]:
try:
shape = factory.create(name)
print(shape.draw())
except ValueError as e:
print(e)
Output
Drawing a circle
Drawing a square
Drawing a triangle
Unknown shape type: hexagon
How it works
The factory pattern centralizes object creation logic in one place. ShapeFactory.create normalizes the input by stripping whitespace and lowercasing, then looks up the class in a dictionary. This avoids long if-elif chains and makes adding new shapes as simple as adding a new class and a dictionary entry. Raising a ValueError for unknown types gives clear feedback at runtime, and the NotImplementedError in the base Shape enforces that subclasses implement draw.
Common mistakes
- Forgetting to normalize input (stem casing or whitespace) leading to KeyError
- Raising KeyError instead of converting it to a more descriptive exception
Variations
- Use a class-level registry dict and `__init_subclass__` to auto-register shapes.
- Create a module-level function `create_shape(shape_type)` instead of a static method.
Real-world use cases
- Game engines instantiate enemies or items based on a string from level data.
- Serialization libraries deserialize different object types from JSON type tags.
- Plugin systems load modules by name from configuration files at runtime.
Sponsored
More from OOP & classes
- Add property getter setter validation in Python easy
- Binary Tree Inorder Traversal in Python easy
- Borg pattern shared state in Python medium
- Bridge Pattern in Python: Separate Abstraction from Implementation medium
- Composable Predicates with the &, |, ~ Operators in Python medium
- Composition over Inheritance: How to Build a Wallet Account in Python easy
Keep learning
Related tutorials and quizzes for this topic.