Python implementing Singleton as metaclass , but for abstract classes
Question: 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()
    


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

