Python Forum
dynamically creating a subclass
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
dynamically creating a subclass
#1
I have a situation where I know what superclass I am creating (using the superclass sort of like a java abstract class), and will be receiving an string argument to control which type of subclass I return. Here is a simplified snippet that accomplishes what I'm trying to do:

class Person:
    def __init__(self, pet_types):
        self.pets = [Pet().factory(t) for t in pet_types]
      
        
    def get_pets(self):
        print([pet.name for pet in self.pets])
        
    
class Pet:
    def factory(self, t):
        klass = next((cls for cls in self.__class__.__subclasses__() if cls.__name__ == t), self.__class__)
        return klass()
        
    def __init__(self):
        self.name = 'unknown'
        
        
class Cat(Pet):
    def __init__(self):
        self.name = 'Garfield'
    
class Dog(Pet):
    def __init__(self):
        self.name = 'Fido'

Person(['Cat', 'Dog', 'Bird']).get_pets()
It works, but I'm wondering if there is a more pythonic (or just, programming practices in general) way of doing this. Or if this is a "code smell". For context, I'm receiving a json file which defines object types.
Reply
#2
Do they HAVE to be strings? I think the more pythonic way would be to just pass classes that should be instanciated:
Person([Cat, Dog, Bird]).get_pets()
Reply
#3
If you really need to convert strings, you could use a metaclass to collect the subclasses

class PetMeta(type):
    pet_classes = {}

    def __new__(cls, clsname, superclasses, attributedict):
        if clsname in cls.pet_classes:
            raise ValueError(
                "Redefinition of Pet subclass '{}'".format(clsname))
        tp = type.__new__(cls, clsname, superclasses, attributedict)
        cls.pet_classes[clsname] = tp
        return tp

def pet_class(name):
    return PetMeta.pet_classes[name]

class Person:
    def __init__(self, pet_types):
        self.pets = [pet_class(t)() for t in pet_types]

class Pet(metaclass=PetMeta): pass
class Dog(Pet): pass
class Cat(Pet): pass
class Bird(Pet): pass

john = Person(['Dog', 'Cat'])
print(john.pets)
The drawback of __subclasses__() is that it only knows direct subclasses.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Subclass initialized property used in parent class method. Is it bad coding practice? saavedra29 5 1,685 Feb-07-2022, 07:29 PM
Last Post: saavedra29
Star Recursively convert nested dicts to dict subclass Alfalfa 1 2,840 Jan-22-2021, 05:43 AM
Last Post: buran
  use of subclass ebolisa 4 2,172 Sep-17-2020, 01:08 PM
Last Post: jefsummers
  Accessing subclass with a variable David_S 2 2,101 May-19-2020, 05:55 PM
Last Post: David_S
  How can I create a subclass of XlsxWriter? aquerci 2 2,029 May-04-2020, 07:41 PM
Last Post: aquerci
  Design Pattern for accessing subclass attributes UGuntupalli 2 2,050 Jul-30-2019, 11:09 PM
Last Post: UGuntupalli
  Help creating a class instance dynamically Kotevski 9 5,301 Aug-17-2018, 05:23 AM
Last Post: Gribouillis
  Creating folders dynamically with year/month/date sritsv 0 6,313 Oct-16-2017, 03:44 PM
Last Post: sritsv

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020