У меня проблемы с внедрением простой в использовании абстрактной фабрики.Реализация фабричного шаблона Python с метаклассом
Цель
Чтобы иметь возможность определить конкретные заводы таким образом:
class MyConcreteFactory(...):
@classmethod
def __load(cls, key):
obj = ... # Loading instructions here
return obj
Чтобы иметь возможность использовать concretre заводы этот путь
obj = MyConcreteFactory[key]
Моя попытка
Я попытался для определения метакласса для заводов, которые переопределяют оператор скобки и инкапсулируют е заводы модель:
class __FactoryMeta(type):
__ressources = {}
@classmethod
def __getitem__(cls, key):
if key not in cls.__ressources:
cls.__ressources[key] = cls.__load(key)
return cls.__ressources[key]
@classmethod
def __load(cls, key):
raise NotImplementedError
class ConcreteFactory(metaclass=__FactoryMeta):
@classmethod
def __load(cls, key):
return "toto"
a = ConcreteFactory["mykey"]
print(a)
Выпуска
Это не удалось, потому что метод __load называется это один из метакласса, а не один из конкретного класса. Результат:
Traceback (most recent call last):
File "C:\Users\walter\workspace\Game\src\core\factories.py", line 34, in <module>
a = ConcreteFactory["mykey"]
File "C:\Users\walter\workspace\Game\src\core\factories.py", line 19, in __getitem__
cls.__ressources[key] = cls.__load(key)
File "C:\Users\walter\workspace\Game\src\core\factories.py", line 24, in __load
raise NotImplementedError
NotImplementedError
Я попытался удалить метод __load из мета-класса, но затем я получил это (предсказуемую) ошибку:
Traceback (most recent call last):
File "C:\Users\walter\workspace\Game\src\core\factories.py", line 30, in <module>
a = ConcreteFactory["mykey"]
File "C:\Users\walter\workspace\Game\src\core\factories.py", line 19, in __getitem__
cls.__ressources[key] = cls.__load(key)
AttributeError: type object '__FactoryMeta' has no attribute '_FactoryMeta__load'
Вопросы
Есть ли способ доступа метод класса из метакласса? Я ошибаюсь и должен делать это по-другому? Тогда каким образом?
Решение
class __FactoryMeta(type):
ressources = {}
def __getitem__(cls, key):
if key not in cls.ressources:
cls.ressources[key] = cls.load(key)
return cls.ressources[key]
def load(cls, key):
raise NotImplementedError
class ConcreteFactory(metaclass=__FactoryMeta):
@classmethod
def load(cls, key):
return "toto"
a = ConcreteFactory["mykey"]
print(a)
По крайней мере, часть вашей проблемы связана с названием mangling, см., Например, http://stackoverflow.com/q/7456807/3001761 – jonrsharpe
Не является метаклассом (почти) только примером, где двойное подчеркивание не является плохой практикой? –
Джон прав. '__name' получает искаженный интерпретатор с явной целью сделать его недоступным для суперкласса. Измените '__load' на' _load', и вы избавитесь от ошибки _that_ (хотя у вас могут быть и некоторые из '__resources' тоже - в зависимости от того, как вы используете' __getitem__', в подклассах). – mgilson