Дизайн класса Python с метаклассом - PullRequest
1 голос
/ 24 марта 2019

У меня есть дизайн класса, в котором классы 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 действительно выглядит как нечто, что в некотором смысле вполне можно назвать «метаклассом» (технически, а не с точки зренияterminus technicus метакласс используется в ООП, но в терминах: он полностью описывает поведение дочерних классов).

Итак, мне интересно: есть ли другой (лучший) дизайнклассов, чтобы отразить мою структуру?Должен ли я использовать метакласс для обеспечения существования parameters, или есть лучший способ сделать это?Или я должен просто уйти в отставку, чтобы обеспечить существование переменной класса parameters в классах Children?

1 Ответ

1 голос
/ 24 марта 2019

Если вы используете 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
...