Я работаю над большой структурой, которая работает с Mixin для регистрации дескрипторов функций классов в центральном элементе, который предоставляет API для конечного пользователя. Теперь у меня есть 2 разные аппаратные установки, которые в целом очень похожи и имеют очень большое общее подмножество функций, но обе они имеют дополнительные функции для регистрации.
Итак, я поместил общее подмножество функциональности в абстрактный базовый класс (в следующем примере «Bar»), который наследуется от Mixin. Оба аппаратных класса ("Foo" и "Foo2") наследуются от "Bar", но также и от Mixin, что приводит к двойному вызову Mixin. init () во время фазы инициализации любого из "Foo" "или" Foo2 "
from abc import ABC, abstractmethod
import inspect
class FunctionHandler:
function_register = dict()
@staticmethod
def register_function(stuff, register):
if register not in FunctionHandler.function_register.keys():
FunctionHandler.function_register[register] = list()
FunctionHandler.function_register[register].append(stuff)
class Mixin(ABC):
def __init__(self):
ABC.__init__(self)
# only call mix in the highest level of inheritance
if not inspect.stack()[2].function == "__init__":
self.mix()
@abstractmethod
def mix(self):
raise NotImplementedError
def register_stuff(self, stuff, register):
FunctionHandler.register_function(stuff, register)
class Bar(Mixin, ABC):
def __init__(self):
ABC.__init__(self)
self.name = "bar"
Mixin.__init__(self)
def mix(self):
# register a lot of stuff common to all inheriting classes
self.register_stuff("bar", self.name)
self.register_stuff("bar2", self.name)
class Foo(Bar, Mixin):
def __init__(self):
Bar.__init__(self)
self.name = "foo"
Mixin.__init__(self)
def mix(self):
Bar.mix(self)
self.register_stuff("foo", self.name)
class Foo2(Bar, Mixin):
def __init__(self):
Bar.__init__(self)
self.name = "foo2"
Mixin.__init__(self)
def mix(self):
Bar.mix(self)
self.register_stuff("foo2", self.name)
if __name__ == "__main__":
foo = Foo()
foo2 = Foo2()
print(FunctionHandler.function_register)
Мой желаемый результат для этого примера:
{'foo': ['bar', 'bar2', 'foo'], 'foo2': ['bar', 'bar2', 'foo2']}
Двойная инициализация этого миксина приводит к ненужным записям в регистре функций, которых я хотел бы избежать.
Мое текущее решение состоит в том, чтобы вызывать self.mix () из Mixin только в том случае, если вызывающий класс находится на самом верху наследования (для классов, которые не являются базовыми классами другого потомка) с inspect.stack () состояние:
if not inspect.stack()[2].function == "__init__":
self.mix()
Как вы можете проверить, результат без этого условия:
{'foo2': ['bar', 'bar2', 'foo2'], 'foo': ['bar', 'bar2', 'foo'], 'bar': ['bar', 'bar2', 'foo', 'bar', 'bar2', 'foo2']}
Так что в целом мое решение работает, однако я не полностью им удовлетворен, так как условие сравнения строк в стеке вызовов кажется мне немного небезопасным.
Так что для меня есть 2 вопроса:
Разве моя концепция не оптимальна, так что этот двойной Mixin. init () происходит в первую очередь? Если да, как эта структура могла бы быть реализована лучше?
Если концепция в целом в порядке, есть ли способ проверить «глубину наследования», чтобы я мог проверить это вместо имени функции стека вызовов?