В attrs
порядок аргументов сгенерированного метода init
определяется порядком определения атрибута в классе + MRO (стандартный способ определения общего порядка на основе множественных отношений наследования).Это не очень хорошо для моего варианта использования, но, похоже, нет никакой гибкости.Вот пример использования:
Я использую attrs
для определения некоторых классов, моделирующих графические примитивы.Эти примитивы связаны с тем, что им всем нужны данные для работы и создания графики с заданными высотой и шириной, которые имеют значение по умолчанию.Таким образом, на верхнем уровне есть класс
@attr.s
class BaseGraphics:
data = attr.ib()
height = attr.ib(default=300)
width = attr.ib(default=400)
. Производные от этого есть три класса, UnivariateGraphics
, BivariateGraphics
и MultivariateGraphics
, которые используют один, два или более столбцов в data
соответственно.Позвольте мне показать один из них:
@attr.s
class BivariateGraphics(BaseGraphics):
x = attr.ib()
y = attr.ib()
Одномерный регистр имеет только x
, а многомерный регистр - как один columns
атрибут.Это терпит неудачу, потому что в MRO x
и y
идут после height
и width
, но x
и y
являются обязательными, тогда как height
и width
не обязательны.Точная ошибка:
ValueError: No mandatory attributes allowed after an attribute with
a default value or factory. Attribute in question:
Attribute(name='x', default=NOTHING, validator=None, repr=True,
cmp=True, hash=None, init=True, metadata=mappingproxy({}), type=None,
converter=None, kw_only=False)
. Я могу установить значение по умолчанию для x
и y
, как в первом и втором столбце, но все равно порядок будет неправильным.Например, если вы хотите написать что-то вроде
BivariateGraphics(iris_data, "petalWidth", "sepalWidth")
, второй и третий аргументы будут интерпретироваться как height
и width
, а не x
и y
.Я могу предотвратить эту ошибку, создав все атрибуты, кроме data
только для ключевых слов, но я не могу поддерживать этот синтаксис.Из прочтения нескольких связанных вопросов, например, № 38, кажется, что это рекомендуемый подход.Близко, но без сигары.
Другим обходным решением будет добавление height
и width
к каждому производному классу независимо.Это будет нарушением принципа СУХОЙ и не сможет выразить и усилить эту общность между классами.Есть более трех классов, и это будет довольно неприятно.
Это не просто "академический" вопрос.Я использую attrs
в пакете, autosig
, чтобы помочь определить API согласованным образом.Это, в свою очередь, используется в пакете статистической графики altair_recipes
, где на самом деле возникает описанная выше ситуация (ну, в следующем выпуске, когда мне нужно добавить height
и width
ко всем графическим примитивам).
Я мог бы подать проблему разработчикам, но поскольку главный разработчик в шутку (?) Угрожал людям, которые занимаются электрошоком подкласса, я чувствую, что это будет бесполезно.Я был бы заинтересован в решении, не основанном на наследовании, которое не требует нарушений СУХОЙ или сковороды.Спасибо