python—单例模式与多例模式的区别与创建

文章目录

    • 一、单例模式创建
      • 1.通过类方法创建
      • 2. 通过装饰器方法来创建
      • 3. 通过__new__方法来创建
      • 4. 通过模块创建
    • 二、多例模式创建

  单例模式与多例模式最主要的区别是:

单例模式是一个类只有单个对象被创建
多例模式是一个类可以有多个对象被创建

一、单例模式创建

下面展示单例模式的创建过程:

1.通过类方法创建

#!usr/bin/env python
# -*- coding:utf-8 -*-
"""
@author: admin
@file: 类方法.py
@time: 2021/05/24
@desc:
"""

class Custom():

    def __init__(self, name):
        import time
        time.sleep(1)
        self.name = name

    # 通过类方法创建实例
    @classmethod
    def creat_class(cls, *args, **kwargs):
        # 如果没有对象
        if not hasattr(Custom, "_instance"):
            Custom._instance = Custom(*args, **kwargs)
        return Custom._instance

# # 通过类方法来创建类的实例化对象
c1 = Custom.creat_class('张三')
c2 = Custom.creat_class('李四')
print(c1)
print(c2)
print(c1 is c2)  # True
<__main__.Custom object at 0x000002B8CD45F708>
<__main__.Custom object at 0x000002B8CD45F708>
True

但是,使用多线程时,使用类方法创建就会出现问题

#!usr/bin/env python
# -*- coding:utf-8 -*-
"""
@author: admin
@file: 类方法.py
@time: 2021/05/24
@desc:
"""
import threading
import time

class Custom():

    def __init__(self, name):
        import time
        time.sleep(1)
        self.name = name

    # 通过类方法创建实例
    @classmethod
    def creat_class(cls, *args, **kwargs):
        # 如果没有对象
        if not hasattr(Custom, "_instance"):
            Custom._instance = Custom(*args, **kwargs)
        return Custom._instance


def task(arg):
    obj = Custom.creat_class('柳杰')
    print(obj)

for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()
<__main__.Custom object at 0x00000202CBD65148>
<__main__.Custom object at 0x00000202CBD62FC8>
<__main__.Custom object at 0x00000202CBD57048>
<__main__.Custom object at 0x00000202CBD62C08>
<__main__.Custom object at 0x00000202CBD62E88>
<__main__.Custom object at 0x00000202CBD62AC8>
<__main__.Custom object at 0x00000202CBD62988>
<__main__.Custom object at 0x00000202CBD62848>
<__main__.Custom object at 0x00000202CBD65288>
<__main__.Custom object at 0x00000202CBD62D48>

发现创建了不止一个对象!!!
解决办法:加锁!未加锁部分并发执行,加锁部分串行执行,速度降低,但是保证了数据安全

#!usr/bin/env python
# -*- coding:utf-8 -*-
"""
@author: admin
@file: 类方法.py
@time: 2021/05/24
@desc:
"""
import threading
import time

class Custom():
    # 记录实例对象
    _instance_lock = threading.Lock()

    def __init__(self, name):
        import time
        time.sleep(1)
        self.name = name

    # 通过类方法创建实例
    @classmethod
    def creat_class(cls, *args, **kwargs):
        # 如果没有对象
        if not hasattr(Custom, "_instance"):
            with Custom._instance_lock:
                if not hasattr(Custom, "_instance"):
                    Custom._instance = Custom(*args, **kwargs)
        return Custom._instance




def task(arg):
    obj = Custom.creat_class('柳杰')
    print(obj)

for i in range(10):
    t = threading.Thread(target=task,args=[i,])
    t.start()

time.sleep(20)
# 前面已经创建了对象,它就是单例模式
obj = Custom.creat_class()
print('------')
print(obj)
<__main__.custom object at 0x000001C79ABE3208>
<__main__.custom object at 0x000001C79ABE3208>
<__main__.custom object at 0x000001C79ABE3208>
<__main__.custom object at 0x000001C79ABE3208>
<__main__.custom object at 0x000001C79ABE3208>
<__main__.custom object at 0x000001C79ABE3208>
<__main__.custom object at 0x000001C79ABE3208>
<__main__.custom object at 0x000001C79ABE3208>
<__main__.custom object at 0x000001C79ABE3208>
<__main__.custom object at 0x000001C79ABE3208>
------
<__main__.custom object at 0x000001C79ABE3208>

2. 通过装饰器方法来创建

def wer(func):
    # 记录多个类的实例化对象
    _instance = {
     }

    def inner(*args, **kwargs):
        # 如果没有对象
        if func not in _instance:
            # 创建对象并将对象赋值给_instance
            _instance[func] = func(*args, **kwargs)
        return _instance[func]

    return inner


@wer
class Myclass(object):
    pass

m1 = Myclass()
m2 = Myclass()
print(m1)
print(m2)

print(m1 is m2)  # True
<__main__.Myclass object at 0x0000017483B89C08>
<__main__.Myclass object at 0x0000017483B89C08>
True

3. 通过__new__方法来创建

  当我们实现单例时,为了保证线程安全需要在内部加入锁。我们知道,当我们实例化一个对象时,是先执行了类的__new__方法实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所有我们可以重写__new__方法,实现单例模式。

import threading
import time


class Singleton(object):
    _instance_lock = threading.Lock()

    def __init__(self):
        time.sleep(1)

    def __new__(cls, *args, **kwargs):
        if not hasattr(Singleton, "_instance"):
            with Singleton._instance_lock:
                if not hasattr(Singleton, "_instance"):
                    Singleton._instance = object.__new__(cls)
        return Singleton._instance


obj1 = Singleton()
obj2 = Singleton()
print(obj1, obj2)


def task(arg):
    obj = Singleton()
    print(obj)


for i in range(10):
    t = threading.Thread(target=task, args=[i, ])
    t.start()
<__main__.Singleton object at 0x0000026593A073C8> 
<__main__.Singleton object at 0x0000026593A073C8>
<__main__.Singleton object at 0x0000026593A073C8>
<__main__.Singleton object at 0x0000026593A073C8>
<__main__.Singleton object at 0x0000026593A073C8>
<__main__.Singleton object at 0x0000026593A073C8>
<__main__.Singleton object at 0x0000026593A073C8>
<__main__.Singleton object at 0x0000026593A073C8>
<__main__.Singleton object at 0x0000026593A073C8>
<__main__.Singleton object at 0x0000026593A073C8>
<__main__.Singleton object at 0x0000026593A073C8>
<__main__.Singleton object at 0x0000026593A073C8>

4. 通过模块创建

  Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

二、多例模式创建

## 平时我们使用的都是多例模式
class custom():
    pass


c1 = custom()
c2 = custom()
print(c1)  
print(c2)
# 我们可以通过他们的内存地址来判断是否是同一个实例也可以使用is判断
print(c1 is c2)
<__main__.custom object at 0x0000020C6AC28408>
<__main__.custom object at 0x0000020C6AC5CF48>
False

参考:

  • 单例模式与多例模式
  • Python中的单例模式的几种实现方式的及优化

如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论或者私信!
在这里插入图片描述


你可能感兴趣的:(#,基础进阶,python,单例模式,多例模式,创建)