Эта проблема
Предположим, у меня есть перечисление:
from enum import Enum, auto
class Foo(Enum):
DAVE_GROHL = auto()
MR_T = auto()
и я хочу расширить этот класс только с помощью определенных методов (т.е. без новых членов перечисления):
class MixinFoo(Foo):
def catch_phrase(self):
if self is Foo.MR_T:
return "I pity da foo!"
else:
return "There goes my hero!"
Это не удастся с TypeError
, так как по дизайну перечисление не может быть расширено после определения членов. Перечисление Python позволяет вам сделать это в другом направлении (то есть: определить миксин без членов и создать подкласс миксина для добавления членов), но в моем конкретном случае использования определение MixinFoo
перед Foo
использованием в качестве базового класса не вариант (например: Foo
определен в другом модуле, и я не хочу воссоздавать его или изменять код этого модуля).
Что я рассмотрел до сих пор:
Настройка EnumMeta
. EnumMeta
проверяет наличие существующих членов в базовом классе в __prepare__
методе, поэтому может сработать переопределение этого метода и отсрочка проверки в новом метаклассе. К сожалению, EnumMeta
проверка существующих членов в нескольких других функциях и переопределение всех этих функций в целом кажутся плохой практикой (много дублированного кода).
Добавление функций постфактум. Я знаю, что можно сделать что-то вроде:
def catch_phrase(self):
...
Foo.catch_phrase = catch_phrase
и хотя это может работать, есть некоторые существенные недостатки, которых я хотел бы избежать (например: очень громоздкий для большого количества функций, статические методы/методы класса, свойства обычного определения класса могут быть трудно реализовать)
Решение проблемы с композицией над наследованием:
class FooWrapper():
def __init__(self, foo):
self._foo = foo
def catch_phrase(self):
...
Хотя это возможно, я не большой поклонник этого метода.
Некоторые связанные вопросы:
Why does EnumMeta
have checks for existing members outside of __prepare__
? From a design perspective, this seems to not only be redundant, but also makes it unnecessarily difficult to extend the EnumMeta
as in my case. I understand the rationale behind not allowing extension of enums with more members, but mixins were obviously considered in the design of the enum library. Was this an oversight in the design of the enum? Was it considered and rejected? Is it intentional for some reason?
Furthermore, one of the checks for existing members is buried in the _EnumDict
class, which is not accessible, so I'm not sure what I'm trying to do is possible without recreating a fairly substantial portion of the enum library.
Общее намерение состоит в том, что у меня есть общее перечисление, в котором члены известны и фиксированы, но вариант использования и методы зависят от приложения (т. е. разные приложения, которые используют, Foo
будут иметь разные приветствия и, возможно, другие функции для добавления, но ни одному приложению не потребуется добавить другие Foo
s).
Решение проблемы
Работает ли Foo
для вас простое назначение метода?
Как вFoo.catch = lambda self=None: print(Foo if self is None else "MR_T" if self is Foo.MR_T else "Ka-bong")
Если нет, то почему? Для всех целей он ведет себя как метод, и "self" заполняется членом "Foo", если метод вызывается из члена.
Комментариев нет:
Отправить комментарий