What is more a pythonic factory as a function in a module or as a method for the class it creates?

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

The calendar object has only a method that adds events as they are analyzed.

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

I used the iCalendar python module , which implements the factory function as a class method directly in the class, which it returns an instance:

cal = icalendar.Calendar.from_string(data) 

From what little is known about Java, this is a common pattern in Java code, although I seem to find more references to the factory method located on a different class than the class you really want to instantiate from.

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

+4
source share
5 answers

[ Note . Be very careful to separate the "Calendar" from the collection of events, and the "Event" - one event on the calendar. There seems to be some kind of confusion in your question.]

There are many changes to the Factory template.

  • Separate convenience function (e.g. calendarMaker (data))

  • A separate class (e.g. CalendarParser) that creates your target class (Calendar).

  • Class level method (e.g. Calendar.from_string).

They have different goals. All this is Pythonic, questions: "What do you mean?" and "what can change?" Value is everything; change is important.

Pythonic convenience features. Languages ​​like Java cannot have floating functions; you have to wrap a lone function in a class. Python allows you to have a lone function without class overhead. A function matters when your constructor does not have state changes or alternative strategies or any memory from previous actions.

Sometimes people define a class, and then provide a convenient function that creates an instance of the class, sets the usual state and strategy parameters and any other configuration, and then calls the only appropriate class method. This gives you both state and flexibility of a standalone function.

The method template is used at the class level, but it has limitations. First, he has to rely on class-level variables. Because they can be confusing, a complex constructor as a static method runs into problems when you need to add functions (for example, in terms of state or alternative strategies). Make sure that you are never going to extend the static method.

Two, this more or less does not apply to the rest of the methods and attributes of the class. This from_string type is one of many alternative encodings for your Calendar objects. Perhaps you have from_xml , from_JSON , from_YAML and again and again. None of this matters the least for what IS calendar is or what it does. These methods are related to how the calendar is encoded for transmission.

What you'll see in mature Python libraries is that factories are separate from the things they create. Coding (like strings, XML, JSON, YAML) is subject to much more or less random changes. The essential, however, rarely changes.

Separate two issues. Keep the encoding and presentation as far away from state and behavior.

+11
source

This is pythonic, so as not to think about the esoteric difference in some template that you read somewhere, and now you want to use it everywhere, like a factory template.

In most cases, you think of @staticmethod as a solution, it's probably best to use a module function, unless you populate several classes in one module, and each of them has a different implementation of the same interface, then it is better to use the @ method staticmethod

Ultimately, the weather you create with your instances using the @staticmethod, or using a module function, doesn't really matter.

I would probably use the initializer (__init__) of the class, because one of the most acceptable "patterns" in python is that the factory for the class is the initialization of the class.

+6
source

The IMHO method at the module level is a cleaner solution. It hides behind the modular Python system, which gives it a unique namespace prefix, for which the factory pattern is usually used.

+2
source

The factory template has its own strengths and weaknesses . However, choosing one way to instantiate usually has little pragmatic effect for your code.

0
source

The static method rarely matters, but the class method can be useful. It depends on what you want the class and factory function to actually execute.

The A factory function in the module always created an instance of the “correct” type (where the “right” in your case is always the Calendar class, but you can also depend on the contents of what it creates an instance of.)

Use a class if you want it to depend not on data, but on the class you call it on. The class method is similar to staticmethod, because you can call it in the class without an instance, but it gets the class that was called as the first argument. This allows you to actually create an instance of this class, which may be a subclass of the source class. An example of a classmethod is dict.fromkeys (), which creates a dict from a list of keys and a single value (default is None). Since this is a class method, when you subclass dict, you get the "fromkeys" method entirely free. Here is an example of how to write dict.fromkeys ():

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

Source: https://habr.com/ru/post/1277026/


All Articles