简体   繁体   English

带有元类的 Python 类设计

[英]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 .我有一个类设计,其中从某个Parent类继承的Children类只是在某些parameters有所不同,但Parent类包含所有方法,这些方法使用作为Children上的类变量提供的parameters So, in other words, each of my Child classes is fully described by the list of parameters and the inheritance of the Parent class.因此,换句话说,我的每个Child类都由parameters列表和Parent类的继承完全描述。

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.我的实际类有点不同 - 我在Parent类上有越来越复杂的方法以及不同种类的参数 - ,但这是设计原则的最小示例。

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.由于Parent类依赖于它的Children来拥有类变量parameters ,我想,我可能想在每个Child类上强制存在类变量。 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).但另一方面,术语“元类”听起来很适合我的结构,因为Parent确实看起来很像在某种意义上可以称为“元类”的东西(从技术上讲,不是就技术术语而言元类在 OOP 中使用,但就以下方面而言:它完全描述了子类的行为)。

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?我应该使用元类来强制parameters的存在,还是有更好的方法? Or should I just resign to enforce the existence of the parameters class variable on the Children classes in the first place?或者我应该辞职以首先强制子类上的parameters类变量的存在?

If using python3.6 or above, you can accomplish this using __init_subclass__ which I personally reason better with than a metaclass.如果使用 python3.6 或更高版本,您可以使用__init_subclass__完成此操作,我个人认为它比元类更好。

An example of __init_subclass__ based on the usecase described:基于所描述用例的__init_subclass__示例:

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):这会导致在创建BadChild类时(而不是在实例化时) TypeError异常:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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