Pass the child class name as an argument of inherited class method

48 Views Asked by At

how are you doing?

I'm not facing a problem exactly, but I want to improve the code and I don't know how. The 'problem' is:

I have a parent class:

class Utils:

    @staticmethod
    def jsonFromDict(className, dict):
        # code logic here 
        return className(**finalValue)

and then I have a bunch of dataclasses, like:

@dataclass
class payloadA(Utils):

   x: str = ''
   y: str = ''
   z: str = ''

I want to pass the class name to the jsonFromDict without the need to repeat the class name. Today I'm doing in this way:

payloadA.jsonFromDict(payloadA, dict)
payloadB.jsonFromDict(payloadB, dict)
payloadC.jsonFromDict(payloadC, dict)

I don't want to override or to repeat the implementation inside each payload class, but I can't find a way to pass the class name, from the instance which I'm calling the parent's method, to the parent's method.

Is there any way I can do this?

I've tried to override inside each class but I want to keep it DRY

2

There are 2 best solutions below

0
juanpa.arrivillaga On BEST ANSWER

You want an alternative constructor, which and the idiomatic way to do that in Python is with a classmethod. Your base class is acting as a mixin, so I renamed it.

class ConstructorMixin:
    @classmethod
    def jsonFromDict(cls, dict):
        # code logic here 
        return cls(**finalValue)


@dataclass
class PayloadA(ConstructorMixin):

   x: str = ''
   y: str = ''
   z: str = ''


pl = PayloadA.jsonFromDict(some_dict)
1
treuss On

You can use self.__class__.__name__, as the type of self is the child class, even if the method is only declared in the parent class.

Example:

class Father:

    def foo(self):
        print(self.__class__.__name__)

class Son(Father):

    def __init__(self):
        self.foo()

son = Son()

Prints Son.

Edit: Upon re-reading your code, you do not actually want the class name, but the class itself. In that case, you can use self.__class__ and don't need the .__name__. So, another example:

class Father:

    def foo(self):
        return self.__class__("cloned")

class Son(Father):

    def __init__(self, val):
        self.val = val

son = Son("original")
print(type(son), son.val)
otherson = son.foo()
print(type(otherson), otherson.val)