Implementing Singleton as metaclass, but for abstract classes

雨燕双飞 提交于 2019-12-13 02:35:13

问题


I have an abstract class and I would like to implement Singleton pattern for all classes that inherit from my abstract class. I know that my code won't work because there will be metaclass attribute conflict. Any ideas how to solve this?

from abc import ABCMeta, abstractmethod, abstractproperty

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class GenericLogger(object):
    __metaclass__ = ABCMeta

    @abstractproperty
    def SearchLink(self): pass

class Logger(GenericLogger):
    __metaclass__ = Singleton

    @property
    def SearchLink(self): return ''

a = Logger()

回答1:


Create a subclass of ABCMeta:

class SingletonABCMeta(ABCMeta):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(SingletonABCMeta, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


class GenericLogger(object):
    __metaclass__ = SingletonABCMeta

    @abstractproperty
    def SearchLink(self): pass


class Logger(GenericLogger):  
    @property
    def SearchLink(self): return ''

Metaclasses work just like regular classes; you can still create subclasses and extend their functionality. ABCMeta doesn't itself define a __call__ method, so it is safe to add one.

Demo:

>>> from abc import ABCMeta, abstractproperty
>>> class SingletonABCMeta(ABCMeta):
...     _instances = {}
...     def __call__(cls, *args, **kwargs):
...         if cls not in cls._instances:
...             cls._instances[cls] = super(SingletonABCMeta, cls).__call__(*args, **kwargs)
...         return cls._instances[cls]
...
>>> class GenericLogger(object):
...     __metaclass__ = SingletonABCMeta
...     @abstractproperty
...     def SearchLink(self): pass
...
>>> class Logger(GenericLogger):
...     @property
...     def SearchLink(self): return ''
...
>>> Logger()
<__main__.Logger object at 0x1012ace90>
>>> Logger()
<__main__.Logger object at 0x1012ace90>
>>> class IncompleteLogger(GenericLogger):
...     pass
...
>>> IncompleteLogger()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 5, in __call__
TypeError: Can't instantiate abstract class IncompleteLogger with abstract methods SearchLink


来源:https://stackoverflow.com/questions/33364070/implementing-singleton-as-metaclass-but-for-abstract-classes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!