Python中实现单例模式的常见方式有哪些

wufei123 发布于 2023-05-12 阅读(1475)

微信截图_20230307075001.png

Python 中实现单例模式的几种常见方式

元类(Metaclass):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

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):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

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):

1

2

3

4

5

6

7

8

9

10

# 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"# 创建单例实例

1

2

3

4

# 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 方法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

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 免费教程 

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

河南中青旅行社综合资讯 奇遇综合资讯 盛世蓟州综合资讯 综合资讯 游戏百科综合资讯 新闻80915