一文详解Python中实现单例模式的几种常见方式
作者:Dante丶
Python 中实现单例模式的几种常见方式
元类(Metaclass):
class SingletonType(type): """ 单例元类。用于将普通类转换为单例类。 """ _instances = {} # 存储单例实例的字典 def __call__(cls, *args, **kwargs): """ 重写 __call__ 方法。用于创建和返回单例实例。 """ if cls not in cls._instances: # 如果类还没有实例化过 cls._instances[cls] = super().__call__(*args, **kwargs) # 则创建新实例并存储在字典中 return cls._instances[cls] # 返回字典中的实例 class MyClass(metaclass=SingletonType): """ 单例类。使用元类 SingletonType 将其转换为单例类。 """ def __init__(self, name): self.name = name def say_hello(self): print(f"Hello, my name is {self.name}.") # 创建 MyClass 的两个实例,应该是同一个对象 obj1 = MyClass("Alice") obj2 = MyClass("Bob") # 打印两个实例的内存地址,应该相同 print(hex(id(obj1))) # 输出:0x7f8d94547a90 print(hex(id(obj2))) # 输出:0x7f8d94547a90 # 调用两个实例的方法,输出应该相同 obj1.say_hello() # 输出:Hello, my name is Alice. obj2.say_hello() # 输出:Hello, my name is Alice.
在上面的代码中,我们定义了一个名为 SingletonType
的元类,并将其用作 MyClass
的元类。在 SingletonType
类中,我们维护了一个 _instances
字典,用于存储每个类的唯一实例。在 __call__()
方法中,我们检查 _instances
字典,如果类尚未拥有实例,则创建一个新实例并添加到 _instances
中。最后,我们返回 _instances
中的实例。
在 MyClass
类中,我们定义了一个带参数的构造函数,并且使用 metaclass
参数来指定 SingletonType
元类。由于 MyClass
类使用 SingletonType
元类,因此它具有单例行为。在程序中,我们创建了 MyClass
的两个实例 obj1
和 obj2
,然后打印它们的内存地址以验证它们是否是同一个对象。最后,我们调用这两个实例的方法,输出应该相同。
装饰器(Decorator):
def singleton(cls): """ 单例装饰器。用于将普通类转换为单例类。 """ instances = {} # 存储单例实例的字典 def get_instance(*args, **kwargs): """ 获取单例实例的方法。 """ if cls not in instances: # 如果类还没有实例化过 instances[cls] = cls(*args, **kwargs) # 则创建新实例并存储在字典中 return instances[cls] # 返回字典中的实例 return get_instance @singleton class MyClass: """ 单例类。使用装饰器 singleton 将其转换为单例类。 """ def __init__(self, name): self.name = name def say_hello(self): print(f"Hello, my name is {self.name}.") # 创建 MyClass 的两个实例,应该是同一个对象 obj1 = MyClass("Alice") obj2 = MyClass("Bob") # 打印两个实例的内存地址,应该相同 print(hex(id(obj1))) # 输出:0x7f8d94547a90 print(hex(id(obj2))) # 输出:0x7f8d94547
在上面的代码中,我们定义了一个名为 singleton
的装饰器函数。在 singleton
函数内部,我们创建了一个 instances
字典,用于存储每个类的唯一实例。然后,我们定义了一个名为 get_instance
的内部函数,用于获取单例实例。在 get_instance
函数中,我们检查 instances
字典,如果类尚未拥有实例,则创建一个新实例并添加到 instances
中。最后,我们返回字典中的实例。
在 MyClass
类上应用 @singleton
装饰器,以将其转换为单例类。由于该装饰器是针对类进行操作的,因此它可以轻松地将任何普通类转换为单例类。在程序中,我们创建了 MyClass
的两个实例 obj1
和 obj2
,然后打印它们的内存地址以验证它们是否是同一个对象。最后,我们调用这两个实例的方法,输出应该相同。
模块(Module):
# mymodule.py class MyClass: """ 单例类。 """ def __init__(self, name): self.name = name def say_hello(self): print(f"Hello, my name is {self.name}.") my_singleton = MyClass("Alice") # 创建单例实例
# main.py from mymodule import my_singleton # 使用单例实例 my_singleton.say_hello() # 输出:Hello, my name is Alice.
在上面的代码中,我们将 MyClass
类定义在一个独立的模块 mymodule.py
中,并在其中创建了一个单例实例 my_singleton
。然后,在另一个文件 main.py
中,我们从 mymodule
模块中导入 my_singleton
实例,并使用它来调用 say_hello()
方法。
由于 Python 模块在首次导入时会自动执行,因此我们可以利用这一特性来创建单例实例。在 mymodule.py
模块中,我们可以确保 my_singleton
只会被创建一次,并在程序的其他部分中共享它。
new 方法:
class MyClass: """ 单例类。 """ _instance = None # 存储单例实例的类变量 def __new__(cls, *args, **kwargs): """ 重写 __new__ 方法。用于创建和返回单例实例。 """ if cls._instance is None: # 如果类还没有实例化过 cls._instance = super().__new__(cls) # 则创建新实例并存储在类变量中 return cls._instance # 返回类变量中的实例 def __init__(self, name): self.name = name def say_hello(self): print(f"Hello, my name is {self.name}.") # 创建 MyClass 的两个实例,应该是同一个对象 obj1 = MyClass("Alice") obj2 = MyClass("Bob") # 打印两个实例的内存地址,应该相同 print(hex(id(obj1))) # 输出:0x7f8d94547a90 print(hex(id(obj2))) # 输出:0x7f8d94547a90 # 调用两个实例的方法,输出应该相同 obj1.say_hello() # 输出:Hello, my name is Alice. obj2.say_hello() # 输出:Hello, my name is Alice.
在上面的代码中,我们将 MyClass
类的构造函数改为 __new__()
方法,并使用 _instance
类变量来存储单例实例。在 __new__()
方法中,我们检查 _instance
变量,如果类尚未拥有实例,则创建一个新实例并添加到 _instance
中。最后,我们返回 _instance
中的实例。
在程序中,我们创建了 MyClass
的两个实例 obj1
和 obj2
,然后打印它们的内存地址以验证它们是否是同一个对象。最后,我们调用这两个实例的方法,输出应该相同。
无论使用哪种方法实现单例模式,都需要注意线程安全和可扩展性等方面的问题。因此,在实际开发中,请仔细考虑自己的需求并选择合适的实现方式。
以上就是一文详解Python中实现单例模式的几种常见方式的详细内容,更多关于Python 单例模式的资料请关注脚本之家其它相关文章!