Reputation: 61
I have a number of subclasses of a single parent class and want to instantiate them according to strings in serialized data. My approach is to map the instantiating strings to classes and then create corresponding objects using a factory method:
class Superclass:
@classmethod
def get_instance(cls, string):
return CLASSMAP[string]()
def name(self):
pass
class Foo(Superclass):
def name(self):
return "my name is Foo"
class Bar(Superclass):
def name(self):
return "i'm Bar"
class Baz(Superclass):
def name(self):
return "i am called Baz"
CLASSMAP = {
'foo': Foo,
'bar': Bar,
'baz': Baz,
}
I don't like having the CLASSMAP as a global dictionary, but I cannot define it as a member of Superclass right in the declaration due to the subclasses not having been defined yet (and they have to be defined after the superclass, of course). I can of course assign the class map into the class afterwards:
Superclass.CLASSMAP = {...}
and have Superclass' get_instance() method refer to the not-yet-existing field, but it seems even clunkier and prone to errors.
Is there a more Pythonic approach to the whole pattern?
Upvotes: 6
Views: 3296
Reputation: 73450
If you make your super class a new-style class inheriting from object, you can solve this dynamically, using cls.__subclasses__()
:
class Superclass(object):
@classmethod
def get_instance(cls, string):
return next(c for c in cls.__subclasses__() if c.__name__.lower() == string)()
A mixed approach combining the advantage of adding classes dynamically while still having O(1)
class lookup:
class Superclass(object):
@classmethod
def get_instance(cls, string):
return MAPPING[string]()
class Foo(Superclass):
lookup = 'foo'
class Bar(Superclass):
lookup = 'bar'
MAPPING = {c.lookup: c for c in Superclass.__subclasses__()}
Upvotes: 3