python 单例模式

python 单例模式

单例模式是一种设计模式,目的是确保一个类只有一个实例,并提供一个全局访问点来获取该实例。

有些类只需要一个全局唯一的实例,例如数据库连接池、线程池、日志记录器等。使用单例模式可以确保这些类只有一个实例存在,从而避免了资源的浪费和不一致的状态。

单例模式通常包含以下几个要素:

  1. 私有化构造方法:将类的构造方法私有化,使得外部无法直接实例化该类。

  2. 静态实例变量:在类中定义一个静态变量,用来保存类的唯一实例。

  3. 全局访问点:提供一个全局的静态方法或属性,用来获取类的唯一实例。通过该访问点,可以在任何需要使用该实例的地方获取到单例对象。

示例代码如下:

class A(object):
    _instance = None
    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = super(A, cls).__new__(cls, *args, **kw)
        return cls._instance

这段代码定义了一个名为 Conf 的类,它实现了单例模式,并且在多线程环境下保证线程安全。

解释

__new__函数

__new__ 函数在 Python 中创建并返回一个对象实例,在对象创建之前被调用,用来控制对象的创建过程。

__new__ 方法的定义形式如下:

def __new__(cls, *args, **kwargs):
    # 实现代码
    return object.__new__(cls)

cls 参数代表要创建的类本身,*args**kwargs 是用来传递给类的构造方法的参数。

__new__ 方法的作用是创建并返回一个类的实例。可以在对象实例化之前对对象进行定制化的操作。通常情况下不会直接重写 __new__ 方法,而是在类的构造方法 __init__ 中进行对象的初始化和属性赋值。

__new__ 方法通常用于以下情况:

  1. 当需要控制对象的创建过程,或者需要返回一个不可变的对象时,可以重写__new__方法。
  2. 当需要自定义类的实例化过程,或者需要改变实例化的行为时,可以重写__new__方法。

实现过程

  1. A类中定义了一个类变量 _instance,用来保存类的唯一实例。该变量在类的作用域内是全局唯一的。

  2. 在 __new__ 方法中,首先判断 _instance 是否已经存在实例。如果不存在,则通过调用 super(A, cls).__new__(cls, *args, **kw) 创建一个新的实例,并将其赋值给 _instance。这样第一次调用 __new__ 方法时会创建一个新的实例,并将其赋给 _instance。从第二次开始的调用,由于 _instance 已经存在实例,就直接返回该实例。

  3. 无论是创建了新的实例还是直接返回已存在的实例,都会将实例返回。无论多少次调用该类的构造方法,都只会返回同一个实例,实现了单例模式。因为 _instance 是一个类变量,所以它在类的所有实例之间是共享的,保证了只有一个实例被创建和返回。

  4. 这段代码还加入了线程安全的考虑。因为在多线程环境下,可能会有多个线程同时调用该类的构造方法。为了保证线程安全,通过检查 cls._instance 是否已经存在实例,可以避免多个线程同时创建实例的情况,从而保证了线程安全性。

扩展

上面的 cls 可以换成 self 吗

在 __new__ 方法中,cls 是一个约定俗成的参数名,代表当前类本身。虽然可以将 cls 替换为 self,但这是不推荐的做法,因为 self 通常用于表示实例对象,而不是类对象。

在 __new__ 方法中,cls 参数的作用是指明要创建的类。当调用一个类的构造方法时,会自动将类作为第一个参数传递给构造方法,通常我们将该参数命名为 self

而在 __new__ 方法中,由于还没有实例化对象,所以无法使用 self 来表示对象实例。因此使用 cls 来代表要创建的类本身。

cls 和 self 的区别

  • cls:cls 是一个约定俗成的参数名,表示类本身。它在类方法(class method)中使用,用于引用类的属性或调用类的方法。cls 通常作为第一个参数传递给类方法,以区分它与实例方法的不同。通过 cls,我们可以在类方法中访问类的静态成员或创建新的类实例。
class MyClass:
    @classmethod
    def class_method(cls):
        print("This is a class method")

MyClass.class_method()  # 调用类方法
  • self: self 也是一个约定俗成的参数名,表示类的实例本身。它在实例方法(instance method)中使用,用于引用实例的属性或调用实例的方法。self 作为第一个参数传递给实例方法,以便在方法内部访问实例的成员。
class MyClass:
    def __init__(self, name):
        self.name = name

    def instance_method(self):
        print("My name is", self.name)

obj = MyClass("John")
obj.instance_method()  # 调用实例方法

使用场景举例

cls 在类方法中使用,用于引用类的属性或调用类的方法。它通常用于在类方法内部访问类级别的属性或创建新的类实例。

class MyClass:
    class_attribute = "Class Attribute"

    @classmethod
    def class_method(cls):
        print(cls.class_attribute)  # 访问类级别的属性

MyClass.class_method()  # 调用类方法
print(MyClass.class_attribute)  # 直接访问类级别的属性

self在实例方法中使用,用于引用实例的属性或调用实例的方法。它通常用于在实例方法内部访问实例级别的属性或调用其他实例方法。

class MyClass:
    def __init__(self):
        self.instance_attribute = "Instance Attribute"

    def instance_method(self):
        print(self.instance_attribute)  # 访问实例级别的属性

obj = MyClass()
obj.instance_method()  # 调用实例方法
print(obj.instance_attribute)  # 访问实例级别的属性

posted @ 2023-07-28 09:55  JICEY  阅读(219)  评论(0编辑  收藏  举报