Reputation: 4102
Below is a pattern from :https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Factory.html . My question is this, is this still the best idiom/pattern to do generic object creation in Python 3.x? I can't seem to find much on this topic. The code is below:
class Shape(object):
# Create based on class name:
def factory(type):
#return eval(type + "()")
if type == "Circle": return Circle()
if type == "Square": return Square()
assert 0, "Bad shape creation: " + type
factory = staticmethod(factory)
class Circle(Shape):
def draw(self): print("Circle.draw")
def erase(self): print("Circle.erase")
class Square(Shape):
def draw(self): print("Square.draw")
def erase(self): print("Square.erase")
# Generate shape name strings:
def shapeNameGen(n):
types = Shape.__subclasses__()
for i in range(n):
yield random.choice(types).__name__
shapes = \
[ Shape.factory(i) for i in shapeNameGen(7)]
for shape in shapes:
shape.draw()
shape.erase()
You can also create a factory by using the __class__
method as well I've noticed, but I'm unsure of the best way to use this.
Upvotes: 4
Views: 356
Reputation: 78670
I could be missing something, but I don't like this pattern.
You already have factories for Circle
and Square
- Circle
and Square
. :)
The code in your question unnecessarily hardcodes the class names in factory
and then goes through some extra hoops by getting the names of the subclasses of Shape
and then calling factory
with those names.
A more direct way to generate the shapes
list is
types = Shape.__subclasses__()
shapes = [random.choice(types)() for _ in range(7)]
I have a situation where I could have multiple geometries being given. This is an over simplified example, but I am getting JSON response of various geometries, and instead of having to write multiple if statements multiple times, I thought using a Factory could reduce the issue: so Shape(JSON) -> Circle or Shape(JSON) - Square
This does not justify the factory
as it is coded here. You could have a simple dictionary like
classes = {'Circle': Circle, 'Square': Square, ...}
or possibly create it dynamically with
classes = {cls.__name__:cls for cls in Shape.__subclasses__()}
and then call classes[some_string]()
for the instantiation. You can even dynamically instantiate a class by string name using getattr
.
Upvotes: 1