views:

396

answers:

5

I have some Python code that creates a Calendar object based on parsed VEvent objects from and iCalendar file.

The calendar object just has a method that adds events as they get parsed.

Now I want to create a factory function that creates a calendar from a file object, path, or URL.

I've been using the iCalendar python module, which implements a factory function as a class method directly on the Class that it returns an instance of:

cal = icalendar.Calendar.from_string(data)

From what little I know about Java, this is a common pattern in Java code, though I seem to find more references to a factory method being on a different class than the class you actually want to instantiate instances from.

The question is, is this also considered Pythonic ? Or is it considered more pythonic to just create a module-level method as the factory function ?

+6  A: 

It's pythonic not to think about esoteric difference in some pattern you read somewhere and now want to use everywhere, like the factory pattern.

Most of the time you would think of a @staticmethod as a solution it's probably better to use a module function, except when you stuff multiple classes in one module and each has a different implementation of the same interface, then it's better to use a @staticmethod

Ultimately weather you create your instances by a @staticmethod or by module function makes little difference.

I'd probably use the initializer ( __init__ ) of a class because one of the more accepted "patterns" in python is that the factory for a class is the class initialization.

Florian Bösch
The Pythonista says, "muuuuu"
Kevin Conner
"I'd probably use the initializer ( `__init__` ) of a class..." - really? Factory methods are about creation/instantiation, not initialization. By the time `__init__` is called, it's too late, the object has *been* created. If you are going to do some clever factory action in creating new objects as part of some class constructor, it would have to be in `__new__`, not `__init__`.
Paul McGuire
A: 

The factory pattern has its own strengths and weaknesses. However, choosing one way to create instances usually has little pragmatic effect on your code.

SoloBold
+2  A: 

IMHO a module-level method is a cleaner solution. It hides behind the Python module system that gives it a unique namespace prefix, something the "factory pattern" is commonly used for.

Eli Bendersky
+6  A: 

[Note. Be very cautious about separating "Calendar" a collection of events, and "Event" - a single event on a calendar. In your question, it seems like there could be some confusion.]

There are many variations on the Factory design pattern.

  1. A stand-alone convenience function (e.g., calendarMaker(data))

  2. A separate class (e.g., CalendarParser) which builds your target class (Calendar).

  3. A class-level method (e.g. Calendar.from_string) method.

These have different purposes. All are Pythonic, the questions are "what do you mean?" and "what's likely to change?" Meaning is everything; change is important.

Convenience functions are Pythonic. Languages like Java can't have free-floating functions; you must wrap a lonely function in a class. Python allows you to have a lonely function without the overhead of a class. A function is relevant when your constructor has no state changes or alternate strategies or any memory of previous actions.

Sometimes folks will define a class and then provide a convenience function that makes an instance of the class, sets the usual parameters for state and strategy and any other configuration, and then calls the single relevant method of the class. This gives you both the statefulness of class plus the flexibility of a stand-alone function.

The class-level method pattern is used, but it has limitations. One, it's forced to rely on class-level variables. Since these can be confusing, a complex constructor as a static method runs into problems when you need to add features (like statefulness or alternative strategies.) Be sure you're never going to expand the static method.

Two, it's more-or-less irrelevant to the rest of the class methods and attributes. This kind of from_string is just one of many alternative encodings for your Calendar objects. You might have a from_xml, from_JSON, from_YAML and on and on. None of this has the least relevance to what a Calendar IS or what it DOES. These methods are all about how a Calendar is encoded for transmission.

What you'll see in the mature Python libraries is that factories are separate from the things they create. Encoding (as strings, XML, JSON, YAML) is subject to a great deal of more-or-less random change. The essential thing, however, rarely changes.

Separate the two concerns. Keep encoding and representation as far away from state and behavior as you can.

S.Lott
A: 

A staticmethod rarely has value, but a classmethod may be useful. It depends on what you want the class and the factory function to actually do.

A factory function in a module would always make an instance of the 'right' type (where 'right' in your case is the 'Calendar' class always, but you might also make it dependant on the contents of what it is creating the instance out of.)

Use a classmethod if you wish to make it dependant not on the data, but on the class you call it on. A classmethod is like a staticmethod in that you can call it on the class, without an instance, but it receives the class it was called on as first argument. This allows you to actually create an instance of that class, which may be a subclass of the original class. An example of a classmethod is dict.fromkeys(), which creates a dict from a list of keys and a single value (defaulting to None.) Because it's a classmethod, when you subclass dict you get the 'fromkeys' method entirely for free. Here's an example of how one could write dict.fromkeys() oneself:

class dict_with_fromkeys(dict):
    @classmethod
    def fromkeys(cls, keys, value=None):
        self = cls()
        for key in keys:
            self[key] = value
        return self
Thomas Wouters