python单例模式来学习!!


(声明:本教程仅供本人学习使用,如有人使用该技术触犯法律与本人无关)
(如果有错误,还希望指出。共同进步)


【注】参考学习大佬文章 【Python中的单例模式的几种实现方式的及优化】"" 这里 “”


单例模式

单例模式从字面上来理解就是“单个的”、“实例”。
就如同某一个类只有一个实例存在。
多用于某一系统中只允许出现一个实例时。

实现单例模式

1、 __new__方法实现(常用)


__new__() 是在新式类中新出现的方法
作用: 在构造方法__init__()之前进行判断的方法
在Python 中存在于类里面的构造方法__init__()负责将类的实例化,而在__init__()调用之前,new()决定是否要使用该init()方法
原因:__new__()可以调用其他类的构造方法或者直接返回别的对象来作为本类 的实例

【没有加入线程锁】

# __new__()中的参数cls, 代表当前类,此参数在实例化时由python解释器自动识别
class SingleInstance(object):
    _instance = None
    
    def __new__(cls, *args, **kwargs):
        # 也可以这样写
        # if not cls._instance:
        if not hasattr(cls, "_instance"):
            cls._instance = object.__new__(cls)
        return cls._instance


obj1 = SingleInstance()
obj2 = SingleInstance()

print(id(obj1))
print(id(obj2))

# result
# 1662362768
# 1662362768

【加入线程锁,同时创建多个测试】

# !/usr/bin/python
# -*- coding:utf-8 -*-

import threading


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

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls,  "_instance"):
            print(111)
            with SingleInstance._instance_lock:
                # 也可以这样写
                # if not cls._instance:
                if not hasattr(cls, "_instance"):
                    print(222)
                    cls._instance = object.__new__(cls)
        return cls._instance


def task(args):
    obj = SingleInstance()
    # print(args)
    print(id(obj))


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

# print_result
# 可以看出只有第一次实现了实例化,之后直接return已有的实例化
111
222
2219381373080
2219381373080
2219381373080
2219381373080
2219381373080
2219381373080
2219381373080
2219381373080
2219381373080
2219381373080


2、 使用装饰器

def single_instance(cls):
    _instance = dict()

    def inner(*args, **kwargs):
        if cls not in _instance:
            _instance[cls] = cls(*args, **kwargs)
        return _instance[cls]

    return inner

# 下面有注释掉这行的结果,用于测试正确性
@single_instance
class TestModel(object):
    def __init__(self):
        pass


for i in range(5):
    obj = TestModel()
    print(id(obj))

# 装饰器result
2573953818576
2573953818576
2573953818576
2573953818576
2573953818576

# 正常实例化result
2657022795728
2657022985272
2657022861496
2657022795728
2657022985272

3、模块化方法

方法:创建一个py文件,定义一个类,在这个模块中实例化一次,别的模块导入
# single_instance.py
class SingleInstance(object):
    def __init__(self):
        pass


single = SingleInstance()


# 别的模块使用
from single_instance import single 

4、类方法

# !/usr/bin/python
# -*- coding:utf-8 -*-


import threading


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

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

    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with cls._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = cls(*args, **kwargs)
        return cls._instance


def task(*args):
    obj = SingleInstance.instance()
    # print(args)
    print(id(obj))


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


# result
2568173385320
2568173385320
2568173385320
2568173385320
2568173385320
2568173385320
2568173385320
2568173385320
2568173385320
2568173385320

5、指定元类(meatclass)

import threading


# 创建的元类(继承自type)
class SingleInstanceType(type):
    _instance_lock = threading.Lock()

    def __int__(self):
        import time
        time.sleep(1)

    # cls指的是指定元类的类
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with cls._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = super().__call__(cls)
        return cls._instance


# 指定创建的元类(type)为SingletonType
class Test(metaclass=SingleInstanceType):
    def __init__(self, name):
        self.name = name

    def __new__(cls, *args, **kwargs):
        return object.__new__(cls)


def task(*args):
    print("===============================")
    print(args)
    obj = Test(args[0])
    print(id(obj))
    # 这里打印不出来name,不清楚原因。后续补充,或者有大佬可以教学下
    print(obj.name)


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

# result
===============================
(0,)
2006831340624
<class '__main__.Test'>
===============================
(1,)
2006831340624
<class '__main__.Test'>
===============================
(2,)
2006831340624
<class '__main__.Test'>
===============================
(3,)
2006831340624
<class '__main__.Test'>
===============================
(4,)
2006831340624
<class '__main__.Test'>
===============================
(5,)
2006831340624
<class '__main__.Test'>
===============================
(6,)
2006831340624
<class '__main__.Test'>
===============================
(7,)
2006831340624
<class '__main__.Test'>
===============================
(8,)
2006831340624
<class '__main__.Test'>
===============================
(9,)
2006831340624
<class '__main__.Test'>

补充验证


1、关于指定元类(meatclass)中碰到的问题

# 将“5、指定元类(meatclass)”中的部分代码修改成如下
class Test(metaclass=SingleInstanceType):
    def __init__(self, name):
        print(name)
        self.name = name

    def __new__(cls, *args, **kwargs):
        return object.__new__(cls)


def task(*args):
    print("===============================")
    print(args)
    obj = Test(args)
    print(id(obj))
    print(obj.__dict__)


# result
===============================
(0,)
<class '__main__.Test'>
2857797856504
{'name': <class '__main__.Test'>}
===============================
(1,)
2857797856504
{'name': <class '__main__.Test'>}
===============================
(2,)
2857797856504
{'name': <class '__main__.Test'>}
===============================
(3,)
2857797856504
{'name': <class '__main__.Test'>}
===============================
(4,)
2857797856504
{'name': <class '__main__.Test'>}
===============================
(5,)
2857797856504
{'name': <class '__main__.Test'>}
===============================
(6,)
2857797856504
{'name': <class '__main__.Test'>}
===============================
(7,)
2857797856504
{'name': <class '__main__.Test'>}
===============================
(8,)
2857797856504
{'name': <class '__main__.Test'>}
===============================
(9,)
2857797856504
{'name': <class '__main__.Test'>}
- 可以看到打印结果中说明Test类中的name属性存在,并且只在第一次的时候执行了初始化,但是却不是期望中第一个创建单例时的“0”。
- 将线程去掉之后也是同样的问题。
- (后期留坑)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值