Управление порядком аргументов в init производного класса, определенного с помощью attrs
В 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
ко всем графическим примитивам).
Я мог бы подать проблему разработчикам, но поскольку главный разработчик в шутку (?) Угрожал людям, которые занимаются электрошоком подкласса, я чувствую, что это будет бесполезно. Я был бы заинтересован в решении, не основанном на наследовании, которое не требует нарушений СУХОЙ или сковородки. Спасибо
2 ответа
Я решил не использовать наследование и заменить его комбинатором, который действует до генерации классов. Для этого вместо синтаксиса класса я использовал attr.make_class
, который принимает атрибуты как OrderdDict
и выполняет заказ. Следовательно, вышеупомянутый комбинатор - просто способ объединить OrderedDicts
с некоторым соглашением, чтобы определить окончательный порядок. Не уверен, что это проходит обходной путь для достижения статуса ответа, но это заставило меня двигаться.
В таких случаях, когда вы хотите иметь возможность полагаться на стабильные API (особенно при создании подклассов, когда порядок не всегда понятен на первый взгляд), мы настоятельно рекомендуем использовать фабрики методов класса (и это также то, что я склонен использовать в моем собственном коде). Всякий раз, когда вы начинаете что-то менять в своих классах, все может запутаться, особенно если вам приходится перемещаться по нескольким иерархиям. Поэтому лучше создавать API на собственных условиях и использовать attrs только для сантехники.
но так как главный разработчик в шутку (?) угрожал людям, которые занимаются электрошоком
Хотя у меня довольно сильная позиция в отношении подклассов, у меня есть проблемы с представлением о том, что я могу угрожать электрошоком никому, кроме меня, если только это не было подшучиванием под влиянием друзей-единомышленников. Если у меня действительно была такая ошибка, я прошу прощения.