Python 类在每次调用时都继承了单例初始化实例 [英] Python class inherited singleton inits instance on every call

查看:46
本文介绍了Python 类在每次调用时都继承了单例初始化实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试按照here(方法2).回顾这个问题和广泛选择的答案,我尝试实现以下内容:

I'm trying to implement class inherited singleton as described here (Method 2). Going over the question and the extensive chosen answer I tried to implement the following:

class Singleton(object):
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not isinstance(cls._instance, cls):
            cls._instance = object.__new__(cls, *args, **kwargs)
            cls._instance._initialized = False

        return cls._instance

class A(Singleton):
    def __init__(self):
        print "Init is called"

class B(Singleton):
    def __init__(self):
        print "Init is called"

正如您可能猜到的,每当我创建 Class A 时,我都会得到相同的对象,但会调用 __init__.这是有问题的,因为 Class A 可能会因此更改其所有成员.

As you may guess, whenever I create Class A I get the same object, but __init__ is called. This is problematic as the Class A can have all it's members changed due to this.

正在做:

a1 = A()
a2 = A()
print a1 == a2

将导致:

>> Init is called
>> Init is called
>> True

这个问题提出了一个类似的问题,但我不想在那里使用解决方案,因为它不包括继承,我至少有 2 个类需要 Singleton 继承.我试图在 here 实施解决方案,但它没有工作.此处的解决方案有效,但它涉及更改Class AClass B 我不想这样做.

This question poses a similar issue but I would prefer not to use the solution there as it doesn't include the inheritance and I have at least 2 classes that needs the Singleton inheritance. I tried to implement the solution here but it didn't work. The solution here works but it involves changing Class A and Class B which I would prefer not to.

有没有办法改变 Singleton 的实现,这样 __init__ 就不会在每次创建时被调用?(我不能使用元类,因为 AB 都继承了其他类,例如具有自己的元类的抽象类.

Is there a way to change the Singleton implementation so that __init__ won't be called on every creation? (I can't use metaclasses as both A and B inherit other classes e.g. abstract classes with their own metaclasses).

谢谢

推荐答案

在现代 Python 中,这可以通过编写一个 __init_subclass__ 方法来完成,该方法可以装饰 __init__ 使其成为运行前检查cls._instance.

In modern Python this could be done by writting a __init_subclass__ method that could decorate __init__ to make it check cls._instance before running.

事实上,(即你也需要它用于 Python 2) - 我认为更简单的事情是 __new__ 用 NOP 方法修补 __init__ 如果实例已经存在:

As it is, (i.e. you need it for Python 2 as well) - I think the simpler thing is for __new__ to patch __init__ with a NOP method if the instance already exists:


_nop_init = lambda self, *args, **kw: None

class Singleton(object):
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not isinstance(cls._instance, cls):
            cls._instance = object.__new__(cls, *args, **kwargs)
            cls._instance._initialized = False
        # Python 2 have to check in the cls.__dict__ - Py3 could check the attribute directly:
        elif cls.__dict__.get("__init__", None) is not _nop_init:
            cls.__init__ = _nop_init
        return cls._instance

class A(Singleton):
    def __init__(self):
        print "Init is called"

class B(Singleton):
    def __init__(self):
        print "Init is called"

额外信息 调用__init__的语言机制内置于type__call__方法中——Python 中所有类的元类.在实例化目标类时,它会调用目标类的 __new____init__ 方法,因此,使用元类,可以轻松地从自定义元类控制这些调用.有趣的是,当 __new__ 没有返回目标类的实例时,__init__ 不会被调用.(在这种单例情况下,单例 te 类的一个实例,因此它被调用).

extra info The language mechanism to call __init__ is built-in the __call__ method of type - the metaclass for all classes in Python. It will call the __new__ and __init__ method of a target class when instantiating it, and thus, with a metaclass, it is easy to control these calls from a custom metaclass. It is also interesting to note that when __new__ does not return an instance of the target class, __init__ is not called. (In this singleton case, the singleton is an instance of te class, and thus it is called).

真实世界示例:上次我编写单例时,我选择避免在自己的代码中重新运行 __init__ - 因为它是项目中唯一的单例,在 __new__ 中不需要通用代码:https://github.com/jsbueno/pythonchain/blob1f9208dc8bd2741a574adc1bf745d218e4314e4a/pythonchain/block.py#L276

real world example: last time I coded a singleton, I opted for avoiding re-run __init__ in its own code - sine it is the only singleton in the project, tere was no need for generic code for that in a __new__: https://github.com/jsbueno/pythonchain/blob/1f9208dc8bd2741a574adc1bf745d218e4314e4a/pythonchain/block.py#L276

这篇关于Python 类在每次调用时都继承了单例初始化实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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