单例模式中惰性实例化的两个问题

two issues on the lazy instantiation in the Singleton pattern

我的python版本:

python3 --version
Python 3.9.2

问题 1:
isinstance函数是什么意思?

class Singleton1(object):
    __instance = None
    def __init__(self):
        if not hasattr(Singleton1, '__instance'):
            print("__init__ method called, but no instance created")
        else:
            print("instance already created:", self.__instance)
    @classmethod
    def get_instance(cls):
        if not cls.__instance:
            cls.__instance = Singleton1()
        return cls.__instance

初始化它:

x = Singleton1()
__init__ method called, but no instance created

isinstance函数检查一下:

isinstance(x,Singleton1)
True

如果x不是实例,为什么isinstance(x,Singleton1)说它是Singleton1的实例?

问题 2:
为什么无论如何都无法调用 __init__ 方法?

现在将class中的所有__instance(双下划线)替换为_instance(单下划线),将Singleton1替换为Singleton2:

class Singleton2(object):
    _instance = None
    def __init__(self):
        if not hasattr(Singleton2, '_instance'):
            print("__init__ method called, but no instance created")
        else:
            print("instance already created:", self._instance)
    @classmethod
    def get_instance(cls):
        if not cls._instance:
            cls._instance = Singleton2()
        return cls._instance

初始化它:

y = Singleton2()
instance already created: None

为什么__init__方法在这个状态下无论如何都调用不了?

@snakecharmerb on issue1,为什么有人说它是惰性实例化,如果 isinstance(x,Singleton1) 为真,则不需要调用 Singleton1.get_instance() ,因为实例已经创建在实例化。

hasattr 检查并没有按照您的想法进行。使用 Singleton2*hasattr(Singleton2, '_instance') 总是 True,因为 class 有一个名为 _instance 的属性。您想检查实例的 value,因此请改用 getattr;然后将打印预期的输出。

isinstance 检查成功,因为 Singleton2() 每次都会 return 一个新实例 - 没有什么可以阻止这一点。您可以添加一个 __new__ 方法来在每次调用 Singleton2() 时创建 _instance 和 return 它。请注意,这意味着 _instance 将在调用 __init__ 时始终存在。

class Singleton2:

    _instance = None     
       
    def __new__(cls):    
        if cls._instance is not None:    
            return cls._instance    
        instance = super().__new__(cls)    
        cls._instance = instance    
        return instance 

* Singleton1 中的 hasattr 签入由于在 __instance 上执行的名称修改而变得复杂。一般来说,避免使用双下划线变量名,除非在 class 层次结构中避免名称冲突。