Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to instantiate a subclass type variable from an existing superclass type object in Python

I have a situation where I extend a class with several attributes:

class SuperClass:
    def __init__(self, tediously, many, attributes):
        # assign the attributes like "self.attr = attr"

class SubClass:
    def __init__(self, id, **kwargs):
        self.id = id
        super().__init__(**kwargs)

And then I want to create instances, but I understand that this leads to a situation where a subclass can only be instantiated like this:

super_instance = SuperClass(tediously, many, attributes)

sub_instance = SubClass(id, tediously=super_instance.tediously, many=super_instance.many, attributes=super_instance.attributes)

My question is if anything prettier / cleaner can be done to instantiate a subclass by copying a superclass instance's attributes, without having to write a piece of sausage code to manually do it (either in the constructor call, or a constructor function's body)... Something like:

utopic_sub_instance = SubClass(id, **super_instance)
like image 877
peterz Avatar asked Sep 18 '26 02:09

peterz


1 Answers

I managed to finally do it using a combination of an alt constructor and the __dict__ property of the super_instance.

class SuperClass:
    def __init__(self, tediously, many, attributes):
        self.tediously = tediously 
        self.many = many 
        self.attributes = attributes

class SubClass(SuperClass):
    def __init__(self, additional_attribute, tediously, many, attributes):
        self.additional_attribute = additional_attribute
        super().__init__(tediously, many, attributes)

    @classmethod
    def from_super_instance(cls, additional_attribute, super_instance):
        return cls(additional_attribute=additional_attribute, **super_instance.__dict__)

super_instance = SuperClass("tediously", "many", "attributes")

sub_instance = SubClass.from_super_instance("additional_attribute", super_instance)

NOTE: Bear in mind that python executes statements sequentially, so if you want to override the value of an inherited attribute, put super().__init__() before the other assignment statements in SubClass.__init__.

NOTE 2: pydantic has this very nice feature where their BaseModel class auto generates an .__init__() method, helps with attribute type validation and offers a .dict() method for such models (it's basically the same as .__dict__ though).

like image 67
peterz Avatar answered Sep 19 '26 16:09

peterz