一文详解Python中实现单例模式的几种常见方式
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 单例模式的资料请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341