3 ms·
I prefer doing this directly in a registry/factory class, eg: class Registry: constructors = {} @classmethod def register(cls, other):
by ijustlovemath 3y ago
I prefer doing this directly in a registry/factory class, eg:
class Registry:
constructors = {}
@classmethod
def register(cls, other):
# you can do it by an implicit property or the class name in simple cases. It's better not to use implementation details here, eg you should use an explicit class attribute
# you can also verify that the other class holds certain invariants here, so it fails immediately
cls.constructors[other.__name__] = other
# cls.contructors[other.name] = other
@classmethod
def from_name(cls, name):
# error handling code here
return cls.constructors[name]
# in something.py
@Registry.register
class Something:
def __init__(self, foo, bar=None):
self.foo = foo
self.bar = None
# In something_test.py
import something
import registry
smth = registry.from_name("Something")
s = smth('foo', bar=2)
You'll want to have a registry for each base class (they largely all look the same except for the invariant checks), but this way you don't have to update a map, you just add the decorator to new classes as you build them. It also allows classes to be completely unaware of the registry and focus on their actual task.
Additionally, the invariant checking can do all sorts of things that you can't do with a base class, eg making sure that overridden properties are still properties, checking that class attributes follow whatever formatting convention you have, etc etc