Python类设计与元类

问题描述 投票:1回答:1

我有一个类设计,其中继承自某个Children类的Parent类只是在某些parameters中有所不同,但Parent类包含所有方法,它们使用parameters作为类变量提供给Children。换句话说,我的每个Child类都由parameters列表和Parent类的继承完全描述。

所以,比方说,我有以下几个类:

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)

我的实际类有点不同 - 我在Parent类上有越来越复杂的方法,也有不同类型的参数 - 但这只是设计原则的一个最小例子。

由于Parent类依赖于它的Children来获得类变量parameters,我想,我可能想在每个Child类上强制执行类变量的存在。我已经读过,我通过使用元类来实现这一点。但我也读到大多数开发人员不需要使用元类,如果有疑问,你可能不需要它们。我之前从未使用过元类,因此我怀疑是否应该使用它们,因此根据提到的规则,我可能不需要元类。但另一方面,术语“元类”听起来与我的结构非常匹配,因为Parent在某种意义上看起来真的可以被称为“元类”(技术上,不是终端技术的方式)元类在OOP中使用,但就以下方面而言:它完全描述了子类的行为。

所以,我想知道:是否有不同的(更好的)类设计来反映我的结构?我应该使用元类来强制存在parameters,还是有更好的方法呢?或者我应该首先辞职,以便首先在Children类上强制执行parameters类变量?

python oop metaclass
1个回答
1
投票

如果使用python3.6或更高版本,你可以使用__init_subclass__来完成这个,我个人认为它比一个元类更好。

基于描述的用例的__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

这导致在创建TypeError类时(而不是在实例化时)引发BadChild异常:

TypeError: Subclass of <class '__main__.BadChild'> does not have a parameters class attribute
© www.soinside.com 2019 - 2024. All rights reserved.