【问题标题】:Using metaclasses to create a singleton class in python在 python 中使用元类创建单例类
【发布时间】:2014-03-01 09:12:40
【问题描述】:

当我遇到一些让我难过的事情时,我正在搞乱元类,试图弄清楚如何使用元类来创建单例数据结构:

另外,我已经完成了我的作业并查看了this 页面和this 一个,但我想看看我是否可以自己完成,并且出现的问题不是如何在我的单例元类版本中实现单例以及更多关于某些功能的信息。

class SingletonError(Exception):
    pass

class Singleton(type):

    def __new__(metacls, name, parents, kwargs):
        cls = super(Singleton, metacls).__new__(metacls, name, parents, kwargs)
        cls._instance = None
        return cls

    def __call__(cls, *args, **kwargs): #cls is the class being called, in this case
                                        #when Quux is called, the Quux class is sent
                                        #as the cls argument.
        if not cls._instance:
            inst = cls.__new__(cls, *args, **kwargs)
            cls._instance = inst
        else:
            raise SingletonError("Cannot initialize multiple singletons")
        print('returning', cls._instance)
        return cls._instance

class Quux(metaclass = Singleton):
    pass

大部分都有效,就像它在尝试初始化 Quux 的多个实例时确实会引发 SingletonError,但请注意当我尝试创建 Quux 的实例时会发生什么:

>>> q = Quux()
returning <__main__.Quux object at 0x02BE7E90>
>>> type(q)
<class '__main__.Quux'>

这是否意味着单例元类中的__call__ 方法返回的是类对象,而不是__call__ 方法中创建的实例?如果是这样,我该如何使用我当前的设置来修复它

(我意识到有更好的方法来创建单例,但为了这个练习和学习元类,我想用这个设置来解决它)。


编辑:好的,所以 BrenBarn 刚刚指出我做了一个主要的 derp 并认为当它返回类型时它正在返回类,而实际上如果它正在返回类对象它会说。很抱歉造成混乱。

但现在我遇到了一个新问题:假设我有一个用于 Quux 类的 __new__ 方法。

class Quux(metaclass = Singleton):

    def __new__(cls, thing):
        name = cls.__name__
        parents = cls.__bases__
        kwargs = {'thing' : thing}
        return super(Quux, cls).__new__(cls, thing)

它会引发一个 TypeError 说 object.__new__() takes no parameters。如何修复此 __new__ 方法以返回 Quux 类的实例?

【问题讨论】:

  • 我编辑了我的答案来回答你的第二个问题。但是,仅供参考,编辑您的问题以添加一个完全独立的问题通常不是一个好主意。您的问题标题没有反映您的新问题,因此可以回答的人可能找不到它。如果某个问题的答案将您引向一个新问题,该问题并非直接是原始问题的扩展/修改,您应该将其作为一个单独的问题发布。
  • 很抱歉,以后当我对原来的问题有这么大的绕道时,我会记得提出两个单独的问题。感谢您的建议!

标签: python class initialization singleton metaclass


【解决方案1】:

不,它正在返回Quux 的实例。实例的类型是它的类。所以你的Quux 实例的类型是Quux

这与您的元类没有任何关系。这是任何旧的用户定义类的正常行为:

>>> class Foo(object):
...     pass
>>> f = Foo()
>>> type(f)
<class '__main__.Foo'>

Foo 是一个类。 f 是 Foo 的一个实例,所以 type(f) 是 Foo。

回答你的第二个问题:不要将thing 传递给超类。只需return super(Quux, cls).__new__(cls)

【讨论】:

    猜你喜欢
    • 2021-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 1970-01-01
    • 2021-05-11
    • 1970-01-01
    相关资源
    最近更新 更多