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 pandas库中DataFrame对行和列的操作实例讲解
Jun 09 Python
Tensorflow 同时载入多个模型的实例讲解
Jul 27 Python
对python读取CT医学图像的实例详解
Jan 24 Python
python字符串循环左移
Mar 08 Python
在Pycharm中使用GitHub的方法步骤
Jun 13 Python
Django框架 信号调度原理解析
Sep 04 Python
Python3将数据保存为txt文件的方法
Sep 12 Python
使用IDLE的Python shell窗口实例详解
Nov 19 Python
Python脚本如何在bilibili中查找弹幕发送者
Jun 04 Python
python实现mask矩阵示例(根据列表所给元素)
Jul 30 Python
python进度条显示-tqmd模块的实现示例
Aug 23 Python
Django启动时找不到mysqlclient问题解决方案
Nov 11 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
咖啡豆分级制度 咖啡豆等级分类 咖啡豆是按口感分类的吗?
2021/03/05 新手入门
生成静态页面的PHP类
2006/07/15 PHP
c#中的实现php中的preg_replace
2009/12/21 PHP
php格式文件打开的四种方法
2018/02/24 PHP
PHP类的自动加载机制实现方法分析
2019/01/10 PHP
获取页面高度,窗口高度,滚动条高度等参数值getPageSize,getPageScroll
2006/09/22 Javascript
使用jQuery的ajax功能实现的RSS Reader 代码
2009/09/03 Javascript
document.onreadystatechange事件的用法分析
2009/10/17 Javascript
js获取网页高度(详细整理)
2012/12/28 Javascript
jQuery实现iframe父窗体和子窗体的相互调用
2016/06/17 Javascript
Js面试算法详解
2018/04/08 Javascript
vue使用原生js实现滚动页面跟踪导航高亮的示例代码
2018/10/25 Javascript
Vue.js中 v-model 指令的修饰符详解
2018/12/03 Javascript
今天,小程序正式支持 SVG
2019/04/20 Javascript
原生js实现拖拽移动与缩放效果
2020/08/24 Javascript
JavaScript实现浏览器网页自动滚动并点击的示例代码
2020/12/05 Javascript
简单谈谈Python中函数的可变参数
2016/09/02 Python
Python编程之event对象的用法实例分析
2017/03/23 Python
python爬虫框架scrapy实战之爬取京东商城进阶篇
2017/04/24 Python
python中子类调用父类函数的方法示例
2017/08/18 Python
Python3用tkinter和PIL实现看图工具
2018/06/21 Python
django之使用celery-把耗时程序放到celery里面执行的方法
2019/07/12 Python
使用Python打造一款间谍程序的流程分析
2020/02/21 Python
如何在pycharm中安装第三方包
2020/10/27 Python
关于Python3的import问题(pycharm可以运行命令行import错误)
2020/11/18 Python
pycharm配置QtDesigner的超详细方法
2021/01/25 Python
使用CSS3的背景渐变Text Gradient 创建文字颜色渐变
2014/08/19 HTML / CSS
canvas 下载二维码和图片加水印的方法
2018/03/21 HTML / CSS
纽约21世纪百货官网:Century 21
2016/08/27 全球购物
英国最大的独立家具零售商:Furniture Village
2016/09/06 全球购物
餐厅销售主管职责范本
2014/02/19 职场文书
开展读书活动总结
2014/06/30 职场文书
工作作风懒散检讨书
2014/10/29 职场文书
责任书格式
2015/01/29 职场文书
残联2016年全国助残日活动总结
2016/04/01 职场文书
Java Spring Boot 正确读取配置文件中的属性的值
2022/04/20 Java/Android