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 相关文章推荐
github配置使用指南
Nov 18 Python
Python 遍历列表里面序号和值的方法(三种)
Feb 17 Python
Python编写登陆接口的方法
Jul 10 Python
13个最常用的Python深度学习库介绍
Oct 28 Python
kaggle+mnist实现手写字体识别
Jul 26 Python
python_opencv用线段画封闭矩形的实例
Dec 05 Python
python将txt文件读取为字典的示例
Dec 22 Python
TensorFLow 数学运算的示例代码
Apr 21 Python
Python web如何在IIS发布应用过程解析
May 27 Python
pytorch 多分类问题,计算百分比操作
Jul 09 Python
Pytorch实验常用代码段汇总
Nov 19 Python
python实现黄金分割法的示例代码
Apr 28 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
递归列出所有文件和目录
2006/10/09 PHP
3种平台下安装php4经验点滴
2006/10/09 PHP
谨慎使用PHP的引用原因分析
2012/09/06 PHP
CentOS 6.2使用yum安装LAMP以及phpMyadmin详解
2013/06/17 PHP
php检测useragent版本示例
2014/03/24 PHP
PHP中ini_set与ini_get用法实例
2014/11/04 PHP
smarty模板引擎之内建函数用法
2015/03/30 PHP
tp5.0框架隐藏index.php入口文件及模块和控制器的方法分析
2020/02/11 PHP
让innerHTML的脚本也可以运行起来
2006/07/01 Javascript
获取当前网页document.url location.href区别总结
2008/05/10 Javascript
javascript 新浪背投广告实现代码
2009/07/07 Javascript
jQuery CSS()方法改变现有的CSS样式表
2014/09/09 Javascript
JavaScript fontsize方法入门实例(按照指定的尺寸来显示字符串)
2014/10/17 Javascript
javascript自定义in_array()函数实现方法
2015/08/03 Javascript
jquery validate和jquery form 插件组合实现验证表单后AJAX提交
2015/08/26 Javascript
使用CoffeeScrip优美方式编写javascript代码
2015/10/28 Javascript
JavaScript中Array对象用法实例总结
2016/11/29 Javascript
js中的事件委托或是事件代理使用详解
2017/06/23 Javascript
Js中async/await的执行顺序详解
2017/09/22 Javascript
vue.js给动态绑定的radio列表做批量编辑的方法
2018/02/28 Javascript
vue 音乐App QQ音乐搜索列表最新接口跨域设置方法
2018/09/25 Javascript
详解JavaScript函数callee、call、apply的区别
2019/03/08 Javascript
微信小程序开发(二):页面跳转并传参操作示例
2020/06/01 Javascript
详解用js代码触发dom事件的实现方案
2020/06/10 Javascript
django在接受post请求时显示403forbidden实例解析
2018/01/25 Python
Django处理文件上传File Uploads的实例
2018/05/28 Python
python中类的属性和方法介绍
2018/11/27 Python
浅析Django 接收所有文件,前端展示文件(包括视频,文件,图片)ajax请求
2020/03/09 Python
Python如何使用bokeh包和geojson数据绘制地图
2020/03/21 Python
canvas 如何绘制线段的实现方法
2018/07/12 HTML / CSS
boostrap modal 闪现问题的解决方法
2020/09/01 HTML / CSS
个人工作表现评语
2014/04/30 职场文书
申论倡议书范文
2014/05/13 职场文书
道歉情书大全
2015/05/12 职场文书
关于CSS浮动与取消浮动的问题
2021/06/28 HTML / CSS
Python可变与不可变数据和深拷贝与浅拷贝
2022/04/06 Python