Skip to main content
 首页 » 编程设计

python之将 Singleton 实现为元类,但用于抽象类

2025年05月04日10bluestorm

我有一个抽象类,我想为所有从我的抽象类继承的类实现单例模式。我知道我的代码不会工作,因为会有元类属性冲突。有什么解决办法吗?

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

请您参考如下方法:

创建 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 '' 

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

演示:

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