Python 使用元类实现工厂模式
Python factory pattern implementation with metaclass
我在尝试实现易于使用的抽象工厂时遇到问题。
目标
为了能够以这种方式定义具体工厂:
class MyConcreteFactory( ... ):
@classmethod
def __load(cls, key):
obj = ... # Loading instructions here
return obj
能够以这种方式使用混凝土工厂
obj = MyConcreteFactory[key]
我的尝试
我尝试为覆盖括号运算符并封装工厂模式的工厂定义元class:
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 方法是来自元 class 的方法,而不是来自具体 class 的方法。结果是:
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
我试图从元 class 中删除 __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访问class方法?
我错了吗,应该以其他方式做到这一点?那走哪条路呢?
解决方案
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)
您不应在 metaclass 中使用 @classmethod
。 metaclass 的一个实例是 class 本身,所以:
def __getitem__(cls, key):
实际上是class和:
@classmethod
def __getitem__(metacls, key):
获取元class 作为第一个参数。
Eiher case,我相信 metaclasses 会使这个问题变得更加复杂。我相信一个更可行的方法是创建一个基础工厂class,相应地subclass,并使用subclasses实例作为工厂。
我在尝试实现易于使用的抽象工厂时遇到问题。
目标
为了能够以这种方式定义具体工厂:
class MyConcreteFactory( ... ):
@classmethod
def __load(cls, key):
obj = ... # Loading instructions here
return obj
能够以这种方式使用混凝土工厂
obj = MyConcreteFactory[key]
我的尝试
我尝试为覆盖括号运算符并封装工厂模式的工厂定义元class:
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 方法是来自元 class 的方法,而不是来自具体 class 的方法。结果是:
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
我试图从元 class 中删除 __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访问class方法? 我错了吗,应该以其他方式做到这一点?那走哪条路呢?
解决方案
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)
您不应在 metaclass 中使用 @classmethod
。 metaclass 的一个实例是 class 本身,所以:
def __getitem__(cls, key):
实际上是class和:
@classmethod
def __getitem__(metacls, key):
获取元class 作为第一个参数。
Eiher case,我相信 metaclasses 会使这个问题变得更加复杂。我相信一个更可行的方法是创建一个基础工厂class,相应地subclass,并使用subclasses实例作为工厂。