30

Suppose I have a file foo.py containing a class Foo:

class Foo(object):
   def __init__(self, data):
      ...

Now I want to add a function that creates a Foo object in a certain way from raw source data. Should I put it as a static method in Foo or as another separate function?

class Foo(object):
   def __init__(self, data):
      ...
# option 1:
   @staticmethod
   def fromSourceData(sourceData):
      return Foo(processData(sourceData))

# option 2:
def makeFoo(sourceData):
   return Foo(processData(sourceData))

I don't know whether it's more important to be convenient for users:

foo1 = foo.makeFoo(sourceData)

or whether it's more important to maintain clear coupling between the method and the class:

foo1 = foo.Foo.fromSourceData(sourceData)
44

The choice should between a factory function and a third option instead; the class method:

class Foo(object):
   def __init__(self, data):
      ...

   @classmethod
   def fromSourceData(klass, sourceData):
      return klass(processData(sourceData))

Classmethod factories have the added advantage that they are inheritable. You can now create a subclass of Foo, and the inherited factory method would then produce instances of that subclass.

With a choice between a function and a class method, I'd choose the class method. It documents quite clearly what kind of object the factory is going to produce, without having to make this explicit in the function name. This becomes much clearer when you not only have multiple factory methods, but also multiple classes.

Compare the following two alternatives:

foo.Foo.fromFrobnar(...)
foo.Foo.fromSpamNEggs(...)
foo.Foo.someComputedVersion()
foo.Bar.fromFrobnar(...)
foo.Bar.someComputedVersion()

vs.

foo.createFooFromFrobnar()
foo.createFooFromSpamNEggs()
foo.createSomeComputedVersionFoo()
foo.createBarFromFrobnar()
foo.createSomeComputedVersionBar()

Even better, your end-user could import just the Foo class and use it for the various ways you can create it, as you have all the factory methods in one place:

from foo import Foo
Foo()
Foo.fromFrobnar(...)
Foo.fromSpamNEggs(...)
Foo.someComputedVersion()

The stdlib datetime module uses class method factories extensively, and it's API is much the clearer for it.

1

In Python, I usually prefer a class hierarchy over factory methods. Something like:

class Foo(object):
    def __init__(self, data):
        pass

    def method(self, param):
        pass

class SpecialFoo(Foo):
    def __init__(self, param1, param2):
        # Some processing.
        super().__init__(data)

class FromFile(Foo):
    def __init__(self, path):
        # Some processing.
        super().__init__(data)

I'll put the whole hierarchy (and only this one) in a module, say foos.py. The base class Foo usually implements all the methods (and as such, the interface), and is usually not constructed by the users directly. The subclasses are a mean of overwriting the base constructor, and specifying how Foo is to be constructed. Then I'd create a Foo by calling the appropriate constructor, like:

foo1 = mypackage.foos.SpecialFoo(param1, param2)
foo2 = mypackage.foos.FromFile('/path/to/foo')

I find it more elegant and flexible than factories built from static methods, class methods, or module-level functions.

protected by gnat Aug 28 '18 at 9:48

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.