python中实现单例模式
单例模式的目的是一个类有且只有一个实例对象存在,比如在复用类的过程中,可能重复创建多个实例,导致严重浪费内存,此时就适合使用单例模式。
前段时间需要用到单例模式,就称着机会在网上找了找,有包含了__new__方法在内的5种单例模式,就顺便记录于此。
基于模块导入机制的实现
第一次执行程序时编译为.pyc文件,而第二次执行时会直接执行.pyc。基于此机制,可以通过把类和所创建的实例单独写在某模块内,在使用时直接从这么模块中导入即可,这个导入的实例对象即唯一对象。
# test.py文件
class Test(object):
pass
# 创建实例对象
t = Test() # 在其他文件中
from test import t
基于装饰器的实现
def singleton(cls):
instance = None def wrap(*argrs, **kwargs):
nonlocal instance
if instance is None:
instance = cls(*args, **kwargs)
return instance return wrap @singleton
class Test(object): def __init__(self, *args, **kwargs):
pass t1 = Test()
t2 = Test()
print(t1 is t2) # 输出True
基于类(类方法)的实现(这个看别人的博客学来的)
class Test(object):
def __init__(self):
pass
@classmethod
def instance(cls, *args, **kwargs):
# 每次调用此类方法即可创建实例对象
if not hasattr(Test, "_instance"):
Test._instance = Test(*args, **kwargs)
return Test._instance
上述的实现方法在使用多线程时会出现问题,即这种上述实现单例模式不支持多线程
import threading
import time class Test(object): def __init__(self):
time.sleep(2) @classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Test, "_instance"):
Test._instance = Test(*args, **kwargs)
return Test._instance def task(args):
obj = Test.instance()
print(obj) for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
注意,如果上述不用sleep()暂停,执行速度过快时,仍可能存在相同地址
解决方法:加锁
import threading
import time class Test(object):
_instance_lock = threading.Lock() def __init__(self):
time.sleep(2) @classmethod
def instance(cls, *args, **kwargs):
with Test._instance_lock:
if not hasattr(Test, "_instance"):
Test._instance = Test(*args, **kwargs)
return Test._instance def task(args):
obj = Test.instance()
print(obj) for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start() # 检查长时间后是否为单例
time.sleep(20)
obj = Test.instance()
print(obj)
上述方案长时间后虽然仍为单例模式,但是仍处于加锁的状态,可通过将锁的位置放在判断实例是否存在之后,如果不存在需要重新创建时再加锁
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Test, "_instance"):
with Test._instance_lock:
Test._instance = Test(*args, **kwargs)
return Test._instance
上述这种方法的问题在于创建实例对象时是通过调用Test.instance()创建的,而不是常规那样创建
基于__new__方法的实现(最常见)
在创建一个实例对象时,先调用__new__方法,再调用__init__方法
import threading
import time
class Test(object): def __init__(self):
time.sleep(1) def __new__(cls, *args, **kwargs):
if not hasattr(Test, "_instance"):
Test._instance = object.__new__(cls) # 相当于继承
return Test._instance obj1 = Test()
obj2 = Test()
print(obj1, obj2) def task(arg):
obj = Test()
print(obj) for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
也可像之前装饰器一样用一个类属性来判断是否已有创建好的实例对象,如果没有则在__new__中创建,注意必须返回实例对象
这种方法不受线程影响
基于元类方法的实现
python中是类由type创建,在创建时类时会先调用type的__init__方法,然后创建实例对象时会调用type的__call__方法
顺序如下:type的__init__方法(创建类) -> type的__call__方法(类创建实例对象) -> 类的__new__方法(类创建实例对象) -> 类的__init__方法(类初始化实例对象)
元类的使用方式就是写一个继承了type的类,然后在我们所需的类中指定元类(通过metaclass参数),而继承了type的类则可重新定义类的构造函数,单例模式则可在__call__方法中定义
class SingletonType(type):
def __call__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
return cls._instance class Test(metaclass=SingletonType):
def __init__(self):
pass obj1 = Test()
obj2 = Test()
print(obj1,obj2)
注意:在元类中__call__的参数cls指所创建的类
python中实现单例模式的更多相关文章
- Python学习笔记之在Python中实现单例模式
有些时候你的项目中难免需要一些全局唯一的对象,这些对象大多是一些工具性的东西,在Python中实现单例模式并不是什么难事.以下总结几种方法: 使用类装饰器 使用装饰器实现单例类的时候,类本身并不知道自 ...
- Python中的单例模式
在 Python 中,我们可以用多种方法来实现单例模式: 使用模块 使用 __new__ 使用装饰器(decorator) 使用元类(metaclass) # mysingleton.py class ...
- Python中的单例模式的几种实现方式的优缺点及优化
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- Python 中的单例模式
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- Python中的单例模式——装饰器实现剖析
Python中单例模式的实现方法有多种,但在这些方法中属装饰器版本用的广,因为装饰器是基于面向切面编程思想来实现的,具有很高的解耦性和灵活性. 单例模式定义:具有该模式的类只能生成一个实例对象. 先将 ...
- python中的单例模式、元类
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- Python中的单例模式的几种实现方式的及优化
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- python中的单例模式的应用
1 使用__new__方法 class Singleton(object): def __new__(cls, *args, **kw): if not hasattr(cls, ...
- Python中的单例模式的几种实现方式和优化以及pyc文件解释(转)
原文:https://www.cnblogs.com/huchong/p/8244279.html 另一篇关于.pyc文件是什么? 原文: http://blog.sina.com.cn//s/bl ...
随机推荐
- LeetCode解题笔记 - 2. Add Two Numbers
2. Add Two Numbers You are given two non-empty linked lists representing two non-negative integers. ...
- BERT-wwm、BERT-wwm-ext、RoBERTa、SpanBERT、ERNIE2
一.BERT-wwm wwm是Whole Word Masking(对全词进行Mask),它相比于Bert的改进是用Mask标签替换一个完整的词而不是子词,中文和英文不同,英文中最小的Token就是一 ...
- MyEclipse构建maven项目报错
直接上图: 这里有三种方案: 1.检查jdk版本:最好换成1.8版本 项目右键-->build path-->configure build Path; 1.2 点击 libraries ...
- C++ day01-C++的函数和对象
C++的函数和对象 1.1 1 混合型语言 c++以.cpp为文件扩展名,有且只有一个名为main的主函数,因保留了这个面向过程的主函数,所以被称为混合语言 2 注释方式 . C++的注释方式有两种, ...
- apt-get failed:The following signatures were invalid: BADSIG
参考如下链接: https://askubuntu.com/questions/131601/gpg-error-release-the-following-signatures-were-inval ...
- laravel集成workerman,使用异步mysql,redis组件时,报错EventBaseConfig::FEATURE_FDS not supported on Windows
由于laravel项目中集成了workerman,因业务需要,需要使用异步的mysql和redis组件. composer require react/mysql composer require c ...
- Eclipse导入SpringBoot项目pom.xml第一行报错Unknown error
1.网上搜的都说是将SpringBoot2.1.5版本降级到SpringBoot2.1.4版本,感觉这治标不治本啊,以后想升级不是玩完了. 错误如下所示: 参考:https://ask.csdn.ne ...
- Python入门你要懂哪些?
前言 什么是计算机语言 计算机就是一台用来计算的机器,人让计算机干什么计算机就得干什么! 需要通过计算机的语言来控制计算机(也就是编程语言)! 计算机语言其实和人类的语言没有本质的区别,不同点就是交流 ...
- 终于我还是没忍住,用Python爬了一波女神
你学爬虫,最终不还是为了爬妹子 啥也不说,开始福利赠送~ 女神大会 不是知道有多少人知道“懂球帝”这个 APP(网站),又有多少人关注过它的一个栏目“女神大会”,在这里,没有足球,只有女神哦. 画风是 ...
- SpringBoot(二):SpringBoot 热部署
1.配置pom: <dependency> <groupId>org.springframework.boot</groupId> <artifactId&g ...