code base 5000
code base 5000

Reputation: 4102

Using Python Factory Idioms

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

Answers (1)

timgeb
timgeb

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

Related Questions