将单例实现为元类,但用于抽象类 [英] Implementing Singleton as metaclass, but for abstract classes

查看:34
本文介绍了将单例实现为元类,但用于抽象类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个抽象类,我想为从我的抽象类继承的所有类实现单例模式.我知道我的代码不会工作,因为会有元类属性冲突.任何想法如何解决这个问题?

from abc import ABCMeta,abstractmethod,abstractproperty单例类(类型):_实例 = {}def __call__(cls, *args, **kwargs):如果 cls 不在 cls._instances 中:cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)返回 cls._instances[cls]类 GenericLogger(对象):__元类__ = ABCMeta@抽象属性def SearchLink(self): 通过类记录器(GenericLogger):__metaclass__ = 单例@财产def SearchLink(self): 返回 ''a = 记录器()

解决方案

创建ABCMeta的子类:

class SingletonABCMeta(ABCMeta):_实例 = {}def __call__(cls, *args, **kwargs):如果 cls 不在 cls._instances 中:cls._instances[cls] = super(SingletonABCMeta, cls).__call__(*args, **kwargs)返回 cls._instances[cls]类 GenericLogger(对象):__metaclass__ = SingletonABCMeta@抽象属性def SearchLink(self): 通过类记录器(GenericLogger):@财产def SearchLink(self): 返回 ''

元类就像普通类一样工作;您仍然可以创建子类并扩展它们的功能.ABCMeta 本身并没有定义一个 __call__ 方法,所以添加一个是安全的.

演示:

<预><代码>>>>从 abc 导入 ABCMeta,abstractproperty>>>类 SingletonABCMeta(ABCMeta):... _instances = {}... def __call__(cls, *args, **kwargs):...如果 cls 不在 cls._instances 中:... cls._instances[cls] = super(SingletonABCMeta, cls).__call__(*args, **kwargs)...返回 cls._instances[cls]...>>>类 GenericLogger(对象):... __metaclass__ = SingletonABCMeta... @abstractproperty... def SearchLink(self): 通过...>>>类记录器(GenericLogger):... @财产... def SearchLink(self): return ''...>>>记录器()<__main__.Logger 对象在 0x1012ace90>>>>记录器()<__main__.Logger 对象在 0x1012ace90>>>>类 IncompleteLogger(GenericLogger):... 经过...>>>不完整记录器()回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中文件<stdin>",第 5 行,在 __call__ 中TypeError:无法使用抽象方法 SearchLink 实例化抽象类 IncompleteLogger

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()

解决方案

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

这篇关于将单例实现为元类,但用于抽象类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆