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 ...
随机推荐
- [C5W2] Sequence Models - Natural Language Processing and Word Embeddings
第二周 自然语言处理与词嵌入(Natural Language Processing and Word Embeddings) 词汇表征(Word Representation) 上周我们学习了 RN ...
- Java成员变量和局部变量区别
成员变量和局部变量区别 变量根据定义位置的不同,我们给变量起了不同的名字.如下图所示: 区别 在类中的位置不同 (重点) 成员变量:类中,方法外 局部变量:方法中或者方法声明上(形式参数) 作用范围 ...
- 趣谈Linux操作系统学习笔记:第二十八讲
一.引子 磁盘→盘片→磁道→扇区(每个 512 字节) ext* 定义文件系统的格式 二.inode 与块的存储 1.块 2.不用给他分配一块连续的空间 我们可以分散成一个个小块进行存放 1.优点 2 ...
- 分享一下今天遇到的两个问题,一个是关于C语言内存泄漏问题,另一个是关于Linux下grep使用时的问题
C语言内存泄漏问题: 给出如下代码: #include <stdio.h> #include <stdlib.h> int main(){ int *p; p=(int*)ma ...
- 解决上一篇bean.xml中<bean>标签报错“ Error while downloading 'http://www.springframework.org/schema/beans/spring-beans.xsd........”
在xml文件中,头部报错如题 一开始查询,说是头部少了“<?xml version="1.0" encoding="UTF-8"?>”,但是我并没有 ...
- Zabbix 数据清理
目录 Zabbix 数据清理的一系列操作 一.问题 二.解决办法 Zabbix 数据清理的一系列操作 基本信息: Zabbix 版本 4.0.9 MySQL 版本 5.5 一.问题 我们将 Zabbi ...
- 123: The filename, directory name, or volume label syntax is incorrect今天玩nginx的时候报错
今天在win下玩nginx的时候 提示500错误 看了下nginx的logs 提示 123: The filename, directory name, or volume label syntax ...
- 二维码生成 Gma.QrCodeNet (目前测试支持.net4.0及以上,但vs版本2010不可以 NuGet中搜索不到程序包)
1.添加程序包 2.生产二维码方法 #region 二维码 /// <summary> /// 生成二维码 /// </summary> /// <param name= ...
- java基础(18):集合、Iterator迭代器、增强for循环、泛型
1. 集合 1.1 集合介绍 集合,集合是java中提供的一种容器,可以用来存储多个数据. 在前面的学习中,我们知道数据多了,可以使用数组存放或者使用ArrayList集合进行存放数据.那么,集合和数 ...
- Python【day 13】内置函数02
一.作用域相关-2个 1.locals() 参数是空 返回当前位置作用域的所有变量,返回的是字典 当前位置:函数内,返回局部变量 当前位置:函数外,返回全局变量 2.globals() 参数是空 返回 ...