Простой пример моей проблемы:
class AbstractService:
subscribers = []
@classmethod
def subscribe(cls, service):
service.subscribers.append(cls)
@classmethod
@abstractmethod
def notify(cls, payload):
raise NotImplementedError(f"{cls.__name__} not implemented notify()")
class ServiceA(AbstractService):
@classmethod
def notify(cls, payload):
pass
class ServiceB(AbstractService):
@classmethod
def notify(cls, payload):
pass
ServiceB.subscribe(ServiceA)
ServiceA.notify({'message': 'hello'})
Проблема в том, что все службы в этом экземпляре будут иметь общих подписчиков, поэтому я решил создать функцию, которая возвращает абстрактную службу как таковую:
def get_abstract_service():
class AbstractService:
subscribers = []
@classmethod
def subscribe(cls, service):
service.subscribers.append(cls)
@classmethod
@abstractmethod
def notify(cls, payload):
raise NotImplementedError(f"{cls.__name__} not implemented notify()")
return AbstractService
class ServiceA(get_abstract_service()):
@classmethod
def notify(cls, payload):
pass
class ServiceB(get_abstract_service()):
@classmethod
def notify(cls, payload):
pass
ServiceB.subscribe(ServiceA)
ServiceA.notify({'message': 'hello'})
Теперь это работает, потому что подписчики уникальны для каждого класса, наследующего абстрактный сервис.
Проблемы
Правильно ли это для python или шаблон неверен, если да, то что будет норма в этой ситуации
Как мне обработать ввод для AbstractService, если мое решение правильное (для любой функции, которая требует, чтобы этот тип был передан ей)
Спасибо, я думал, что может быть что-то подобное, чего мне не хватало, но я просто не мог его найти, мое решение просто казалось неверным: D.
я бы подошел к этому так:
from __future__ import annotations
class AbstractService:
subscribers: list[AbstractService]
def __init_subclass__(cls, **kw):
super().__init_subclass__(**kw)
cls.subscribers = []
он устанавливает новый экземпляр subscribers
для каждого класса после создания.
edit: кроме того, это также обрабатывает ввод текста с помощью from __future__ import annotations
например
class C:
def f(self) -> C:
...
Маленькая рекомендация: тоже звоните super().__init_subclass__(**__)
. Вы принимаете аргументы ключевых слов, чтобы их можно было передать методу __init_subclass__
, который их ожидает.
Спасибо за это, очень полезно.
Легким решением было бы дать каждому подклассу свою собственную строку
subscribers = []
. Если вы хотите автоматизировать процесс, дайте базовому классу метод__init_subclass__
, который инициализирует список. Ваше «решение» разрушает отношения наследования между классами: каждый подкласс происходит от базового класса совершенно отдельный, и все они имеют одно и то же имя.