python中单例常用的几种实现方法总结


Posted in Python onOctober 13, 2018

前言

最近这两天在看自己之前写的代码,所以正好把用过的东西整理一下,单例模式,在日常的代码工作中也是经常被用到,

所以这里把之前用过的不同方式实现的单例方式整理一下

什么是单例?

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,单例模式是一种对象创建型模式。

那么单例模式有什么用途呢?举个常见的单例模式例子,我们平时使用的电脑上都有一个回收站,在整个操作系统中,回收站只能有一个实例,整个系统都使用这个唯一的实例,而且回收站自行提供自己的实例,因此回收站是单例模式的应用。

装饰器的方式

这种方式也是工作中经常用的一种,用起来也比较方便,代码实现如下

def Singleton(cls):
 _instance = {}

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

 return _singleton

如果我们工作的一个类需要用单例就通过类似下面的方式实现即可:

@Singleton
class A(object):

 def __init__(self, x):
  self.x = x

我个人还是挺喜欢这种方式的

类的方式实现

这里其实有一些问题就需要注意了,先看一下可能出现的错误代码

class Member(object):

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

乍一看这个类好像已经实现了单例,但是这里有一个潜在的问题,就是如果是多线程的情况,这样写就会有问题了,尤其是在当前类的初始化对象里有一些耗时操作时候

例如下面代码:

#! /usr/bin/env python3
# .-*- coding:utf-8 .-*-

import time
import threading
import random


class Member(object):
 
 def __init__(self):
  time.sleep(random.randint(1,3))

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


def task(arg):
 obj = Member.instance()
 print(obj)

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

这段代码的执行结果会出现实例化了多个对象,导致你写的单例就没起到作用

当然自然而然我们会想起加锁,通过锁来控制,所以我们将上面代码进行更改:

#! /usr/bin/env python3
# .-*- coding:utf-8 .-*-


import time
import threading
import random


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

 def __init__(self):
  i = random.randint(1, 3)
  print(i)
  time.sleep(i)

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


def task():
 obj = Member.instance()
 print(obj)

for i in range(5):
 threading.Thread(target=task,).start()

但是上面的代码还有一个问题,就是当我们已经实例化过之后每次调用instance都会去请求锁,所以这点并不好,所以我们将这部分代码再次更改:

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

这样就很好的实现一个可以多线程使用的单例

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python中实现对Timestamp和Datetime及UTC时间之间的转换
Apr 08 Python
在Apache服务器上同时运行多个Django程序的方法
Jul 22 Python
星球大战与Python之间的那些事
Jan 07 Python
Python工程师面试题 与Python Web相关
Jan 14 Python
python装饰器初探(推荐)
Jul 21 Python
Python使用cx_Oracle调用Oracle存储过程的方法示例
Oct 07 Python
Pandas 数据处理,数据清洗详解
Jul 10 Python
pandas 时间格式转换的实现
Jul 06 Python
Python Tensor FLow简单使用方法实例详解
Jan 14 Python
python脚本实现mp4中的音频提取并保存在原目录
Feb 27 Python
Python基于jieba, wordcloud库生成中文词云
May 13 Python
python cv2.resize函数high和width注意事项说明
Jul 05 Python
python中pika模块问题的深入探究
Oct 13 #Python
Pycharm无法使用已经安装Selenium的解决方法
Oct 13 #Python
解决python selenium3启动不了firefox的问题
Oct 13 #Python
selenium + python 获取table数据的示例讲解
Oct 13 #Python
Python3.4 splinter(模拟填写表单)使用方法
Oct 13 #Python
小白入门篇使用Python搭建点击率预估模型
Oct 12 #Python
Python读取txt内容写入xls格式excel中的方法
Oct 11 #Python
You might like
PHP的异常处理类Exception的使用及说明
2012/06/13 PHP
PHP异常处理浅析
2015/05/12 PHP
PHP输出缓冲控制Output Control系列函数详解
2015/07/02 PHP
php+redis实现多台服务器内网存储session并读取示例
2017/01/12 PHP
用apply让javascript函数仅执行一次的代码
2010/06/27 Javascript
ExtJS下书写动态生成的xml(兼容火狐)
2013/04/02 Javascript
Google (Local) Search API的简单使用介绍
2013/11/28 Javascript
为开发者准备的10款最好的jQuery日历插件
2014/02/04 Javascript
jQuery is()函数用法3例
2014/05/06 Javascript
JS获取当前日期时间并定时刷新示例
2021/03/04 Javascript
浅谈Javascript如何实现匀速运动
2014/12/19 Javascript
js实现鼠标感应图片展示的方法
2015/02/27 Javascript
jquery实现简单文字提示效果
2015/12/02 Javascript
js验证框架实现代码分享
2016/05/18 Javascript
Angular和百度地图的结合实例代码
2016/10/19 Javascript
jQuery命名空间与闭包用法示例
2017/01/12 Javascript
微信小程序教程系列之设置标题栏和导航栏(7)
2020/06/29 Javascript
ionic 自定义弹框效果
2017/06/27 Javascript
小程序tab页无法传递参数的方法
2018/08/03 Javascript
详解JavaScript函数callee、call、apply的区别
2019/03/08 Javascript
微信小程序实现拍照画布指定区域生成图片
2019/07/18 Javascript
[01:32]2016国际邀请赛中国区预选赛CDEC战队教练采访
2016/06/26 DOTA
python基于multiprocessing的多进程创建方法
2015/06/04 Python
关于Python中浮点数精度处理的技巧总结
2017/08/10 Python
详解python3中zipfile模块用法
2018/06/18 Python
python Django 创建应用过程图示详解
2019/07/29 Python
Python+OpenCv制作证件图片生成器的操作方法
2019/08/21 Python
分享30个新鲜的CSS3打造的精美绚丽效果(附演示下载)
2012/12/28 HTML / CSS
施华洛世奇加拿大官网:SWAROVSKI加拿大
2018/06/03 全球购物
Looking4Parking美国:全球排名第一的机场停车比较品牌
2019/08/26 全球购物
餐厅楼面部长岗位职责范文
2014/02/16 职场文书
2014年爱国卫生工作总结
2014/11/22 职场文书
2016庆祝教师节新闻稿
2015/11/25 职场文书
django上传文件的三种方式
2021/04/29 Python
PostgreSQL事务回卷实战案例详析
2022/03/25 PostgreSQL
openEuler 搭建java开发环境的详细过程
2022/06/10 Servers