简体   繁体   中英

Python class design with metaclass

I have a class design where the Children classes inheriting from a certain Parent class just differ in some parameters , but the Parent class contains all methods, which are using the parameters provided as class variables on the Children . So, in other words, each of my Child classes is fully described by the list of parameters and the inheritance of the Parent class.

So, let's say, I have the following classes:

class Parent():
    def __init__(self, **kwargs):
        for param in self.__class__.parameters:
            self.setattr(param, kwargs.get(param))

    def compare(self, other):
        for param in self.__class__.parameters:
            if self.getattr(param) != other.getattr(param):
                return False
        return True

class ChildA(Parent):
    parameters = ["length", "height", "width"]
    def __init__(self, **kwargs):
        super().__init__(**kwargs)


class ChildB(Parent):
    parameters = ["color", "taste"]
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

My actual classes are a bit different - I have more and more complex methods on the Parent class and also different kinds of parameters - , but this is sort of a minimum example of the design principle.

Since Parent class is relying on its Children to have the class variable parameters , I thought, I might want to enforce the existence of the class variable on each Child class. I have read that I achieve this by using a metaclass. But I have also read that most developers do not need to use metaclasses, and if in doubt, you probably don't need them. I have never worked with metaclasses before, and so I am in doubt whether I should use them, and so by that rule mentioned, I probably do not need a metaclass. But on the other hand, the term "metaclass" just sounds like a good match to my structure, since Parent really looks like something which could well be called "metaclass" in some sense (technically, not in terms of the way the terminus technicus metaclass is used in OOP, but in terms of: it is fully describing the behaviour of the children classes).

So, I wonder: Is there a different (better) design of classes to reflect my structure? Should I use a metaclass to enforce the existence of the parameters , or is there a better way to do so? Or should I just resign to enforce the existence of the parameters class variable on the Children classes in the first place?

If using python3.6 or above, you can accomplish this using __init_subclass__ which I personally reason better with than a metaclass.

An example of __init_subclass__ based on the usecase described:

class Parent:
    def __init_subclass__(cls):
        if not hasattr(cls, 'parameters'):
          raise TypeError(f'Subclass of {cls} does not have a parameters class attribute')

    def __init__(self, **kwargs):
        for param in self.__class__.parameters:
            self.setattr(param, kwargs.get(param))

    def compare(self, other):
        for param in self.__class__.parameters:
            if self.getattr(param) != other.getattr(param):
                return False
        return True


class GoodChild(Parent):
    parameters = ['length', 'height', 'width']


class BadChild(Parent):
    pass

Which results in raising a TypeError exception when the BadChild class is created (not when it is instantiated):

TypeError: Subclass of <class '__main__.BadChild'> does not have a parameters class attribute

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM