Python factory pattern implementation with metaclass -
i have issues trying implement easy use abstract factory.
goal
to able define concrete factories way :
class myconcretefactory( ... ): @classmethod def __load(cls, key): obj = ... # loading instructions here return obj
to able use concretre factories way
obj = myconcretefactory[key]
my attempt
i tried define metaclass factories wich override bracket operator , encapsulate factory pattern :
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" = concretefactory["mykey"] print(a)
issue
this failed because __load method called 1 metaclass , not 1 concrete class. result :
traceback (most recent call last): file "c:\users\walter\workspace\game\src\core\factories.py", line 34, in <module> = 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
i tried remove __load method meta class got (predictable) error :
traceback (most recent call last): file "c:\users\walter\workspace\game\src\core\factories.py", line 30, in <module> = 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'
questions
is there way access class method metaclass ? wrong , should in other way ? wich way ?
solution
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" = concretefactory["mykey"] print(a)
you should not use @classmethod
in metaclass. instance of metaclass class so:
def __getitem__(cls, key):
is class and:
@classmethod def __getitem__(metacls, key):
gets metaclass first argument.
eiher case, believe metaclasses make problem more complicated. believe more viable approach create base factory class, subclass accordingly, , use subclass'es instance factory.
Comments
Post a Comment