【问题标题】:Python: make a derived class into a singletonPython:将派生类变成单例
【发布时间】:2020-12-02 01:06:51
【问题描述】:

我想在 python 中将我的派生类变成一个单例。我想通过元类实现单例,但总是遇到以下错误:

TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

我的代码:

# singleton.py
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]

# base.py
from abc import ABC, abstractmethod

class Base(ABC):
    @abstractmethod
    def run(self, value):
        pass

# foo.py
from base import Base
from singleton import Singleton

class Foo(Base, metaclass=Singleton):
    def run(self, value):
        print(value)

# main.py
from foo import Foo

f1 = Foo()
print(f1)
f1.run(42)
f2 = Foo()
print(f2)
f2.run(24)

【问题讨论】:

    标签: python


    【解决方案1】:

    通过其他各种 stackoverflow 问题,我现在自己想出了一个解决方案。

    正如错误文本所述,Foo 的元类必须是与基类元类 (=ABCMeta) 兼容的元类。 这意味着Singleton 也必须继承自ABCMeta

    新代码:

    # singleton.py
    
    from abc import ABCMeta
    
    class Singleton(ABCMeta):
        # ...
    
    # bar.py
    from base import Base
    
    class Bar(Base):
        def run(self, value):
            print(value)
    
    # main.py
    from foo import Foo
    from bar import Bar
    
    f1 = Foo()
    print(f1)
    f1.run(42)
    f2 = Foo()
    print(f2)
    f2.run(34)
    
    b1 = Bar()
    print(b1)
    b1.run(12)
    b2 = Bar()
    print(b2)
    b2.run(21)
    

    输出:

    <foo.Foo object at 0x000001D4D512BE48>
    42
    <foo.Foo object at 0x000001D4D512BE48>
    34
    <bar.Bar object at 0x000001D4D512B0B8>
    12
    <bar.Bar object at 0x000001D4D512BEF0>
    21
    

    所以Foo 是单例,Bar 不是。

    额外问题:

    为什么Singleton(ABC) 不起作用?

    【讨论】:

    • ABC 只是一个基类.. 而不是元类.. 您可以从另一个元类派生一个元类,而不仅仅是从另一个类..
    • Base 派生自 ABC。这给了Base 元类ABCMeta。为什么这也不适用于(元)类Singleton
    • 那么,您似乎只是将“class Singleton(type):”替换为“class Singleton(ABCMeta):”? “类型”是用来做什么的?这不重要吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-05
    • 2019-09-24
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    相关资源
    最近更新 更多