(声明:本教程仅供本人学习使用,如有人使用该技术触犯法律与本人无关)
(如果有错误,还希望指出。共同进步)
【注】:参考学习大佬文章 【Python中的单例模式的几种实现方式的及优化】"" 这里 “”
单例模式从字面上来理解就是“单个的”、“实例”。
就如同某一个类只有一个实例存在。
多用于某一系统中只允许出现一个实例时。
__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
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
方法:创建一个py文件,定义一个类,在这个模块中实例化一次,别的模块导入
# single_instance.py
class SingleInstance(object):
def __init__(self):
pass
single = SingleInstance()
# 别的模块使用
from single_instance import single
# !/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
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'>