I'm trying to write a factory class that essentially provides a user-friendly frontend to creating objects of different kinds depending on keywords. So the user will just have to import this module, and then use module.factory.make_new
with the relevant keywords.
The directory structure will be pretty flat: this file will sit in a directory along with SubclassA.py
which defines the class SubclassA
likewise for SubclassB
etc. That is, each subclass is in its own module of the same name.
If the user wants to dig a bit deeper, they can provide their extension to the code by writing SubclassC.py
which provides class SubclassC
and then add the line factory.register_format("subclassc", "SubclassC")
to the bottom of this file (or, eventually, this will be handled by a config file). Here's what I have so far:
import importlib
class TrackerFactory:
def __init__(self):
self.subclass_dict = {}
def register_format(self, subclass_name, subclass_package):
fmt = importlib.import_module(subclass_package)
self.subclass_dict[subclass_name] = getattr(fmt, subclass_package)
def make_new(self, subclass, **kwargs):
return self.subclass_dict[subclass](subclass, **kwargs)
factory = TrackerFactory()
factory.register_format("subclassA", "SubclassA")
factory.register_format("subclassB", "SubclassB")
I'm just wondering what the possible downsides of this sort of approach are, and what kind of gotchas I might have to look out for. Is there a better way to do this? I get the feeling I can achieve what I want with class methods and a class variable dictionary, and thus avoid hardcoding an instance of the factory, but I couldn't get it to work...
Some things I'm not bothered by:
- sneaky hidden imports not at the top of the file (the advantages of dynamically loading the dependencies of only the registered formats outweigh the poor style, for me). And in any case, this is only used to load a very specific type to module. The modules themselves being loaded in this way (
SubclassA
etc) could have lots of unusual dependencies.
Some things I've already thought of:
- extend the
register_format
method to allow the module name and class name to differ - use some
try
/except
logic - since, in my use case, there will actually be only one or a few objects actually instantiated, I could juggle things around so that the import is actually in
make_new
(andsubclass_dict
just holds a string rather than the function), and then registering a format you won't use that you don't have the dependencies for wouldn't choke.
import_module()
function takes a module name as its first argument, but you are calling itsubtype_name
. Why are you describing a module as though it were a type? (3) All of which makes me think I don't understand your purpose, and I suspect others could be in the same boat. Perhaps you can edit your question to explain both how to set up an intended use case (directory structure and file names) and what the benefits are. \$\endgroup\$SubclassC.py
which provides classSubclassC
. then add the linefactory.register_format("subclassc", "SubclassC")
to the bottom of this file." Are you users editing the file? To double check, users will be editing your library's code? If not can you add the feature to your code. Afterwards I think I could give you a helpful review. \$\endgroup\$