Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么是单身阶级'__调用了两次init_u;()方法?_Python_Python 3.x - Fatal编程技术网

Python 为什么是单身阶级'__调用了两次init_u;()方法?

Python 为什么是单身阶级'__调用了两次init_u;()方法?,python,python-3.x,Python,Python 3.x,为什么foo打印两次 class A: _instance = None def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance def __init__(self, *, var): print('foo')

为什么
foo
打印两次

class A:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self, *, var):
        print('foo')
        self.var = var

a = A(var=1)
b = A(var=2)

assert a == b
assert a.var == b.var
当您编写
A(…)
时,您正在调用

type.__call__(A, ...)
这是因为
type
A
的元类<代码>类型.\uuuuuuuuuuuuu调用\uuuuuuu将依次调用
\uuuuuuuu新建\uuuuuuuuuu
\uuuuuuuuuuu初始化\uuuuuuuuuuu
<如果
\uuuu new\uuuu
返回类的实例,则将始终调用code>\uuuu init\uuuu。以下是一个简化视图:

def __call__(cls, *args, **kwargs):
    self = cls.__new__(cls, *args, **kwargs)
    if isinstance(self, cls):
        cls.__init__(self, *args, **kwargs)
    return self
我能想到的最简单的方法是将所有初始化逻辑放入
\uuuuu new\uuuu

class A:
    _instance = None

    def __new__(cls, *, var):
        if cls._instance is None:
            self = super().__new__(cls)
            self.var = var
            cls._instance = self

        return cls._instance

    def __init__(self, *args, **kwargs):
        print('foo')
当然,
foo
仍然会在每次请求新实例时打印出来,但它确实是一个单例

更全面的方法是重写元类调用方法的行为。这将避免调用
\uuuuu init\uuuuu
,除非调用一次:

class Singleton(type):
    def __call__(cls, *args, **kwargs):
        if hasattr(cls, '_instance'):
            return cls._instance
        return super().__call__(*args, **kwargs)

class A(metaclass=Singleton):
    def __init__(self, *, var):
        print('foo')
        self.var = var

因为每次调用
\uuuuu init\uuuuu
时,都会在
\uuuu new\uuuu
之后调用
。您使
\uuuuuuuuuuuuuuuuu
返回同一个对象的事实并不会阻止
\uuuuuuuuuuuuuuuuu
的执行。如果
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu>将返回现有对象,
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
应该是禁止操作的