mardi 19 avril 2016

Python factory pattern implementation with metaclass

I have issues trying to implement an easy to use abstract factory.

Goal

To be able to define concrete factories this way :

class MyConcreteFactory( ... ):
    @classmethod
    def __load(cls, key):
        obj = ... # Loading instructions here
        return obj

To be able to use concretre factories this way

obj = MyConcreteFactory[key]

My attempt

I tried to define a metaclass for factories wich override bracket operator and encapsulate the 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"


a = ConcreteFactory["mykey"]
print(a)

Issue

This failed because the __load method called is the one from the metaclass and not the one from the concrete class. The result is :

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

I tried to remove the __load method from the meta class but then i got this (predictable) error :

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'

Questions

Is there a way to access class method from a metaclass ? Am i wrong and should do this in an other way ? Then wich way ?

Aucun commentaire:

Enregistrer un commentaire