Python中实现单例的几种方式
Python如何实现单例?
什么是单例模式?
单例模式:一个类只能有一个实例化对象存在的模式。
如何实现单例?
1.使用模块
python中模块是天然的单例模式,当一个模块被调用时,会生成对应的.pyc文件,接下来的每次使用都会自动读取.pyc文件里的内容,因此,要使用模块实现单例,只需这样做:
# mysingleton.py
class Singleton:
def fuc(self):
pass
singleton = Singleton()
我们在使用时只需引用该模块的singleton对象就行了
2.使用装饰器
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:
a = 1 # 类属性
def __init__(self, x):
self.x = x # 类的实例化对象属性
a1 = A(1)
a2 = A(2)
3.使用类
class Singleton:
def __init__(self, *args, **kwargs):
pass
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
上述方式实现的单例模式,在单线程时是可行的,但是在多线程时就会出现问题,假设上述的__init__()方法中有一些耗时的io操作,这里我们用sleep模拟一下:
class Singleton:
def __init__(self, *args, **kwargs):
import time
time.sleep(10)
再用多线程执行创建实例化对象的操作:
import threading
def task(arg):
job = Singleton.instance()
print(job)
for i in range(10):
t = threading.Thread(task,args=[i,])
t.start()
执行结果如下
<__main__.Singleton object at 0x7ff873a9c2d0>
<__main__.Singleton object at 0x7ff873b23e10>
<__main__.Singleton object at 0x7ff873b30850>
<__main__.Singleton object at 0x7ff873b30350>
<__main__.Singleton object at 0x7ff873b30710>
<__main__.Singleton object at 0x7ff873b23f50>
<__main__.Singleton object at 0x7ff873b305d0>
<__main__.Singleton object at 0x7ff873b30490>
<__main__.Singleton object at 0x7ff873b30210>
<__main__.Singleton object at 0x7ff873b300d0>
从执行结果中我们可以发现:在多线程情况之下,通过上述方式创建的实例化对象,内存地址并不一样,这也就意味着我们并没有实现单例模式。那么,为什么这种单例模式的写法无法在多线程情况下奏效呢?
在搞清楚这个问题之前,我们需要先了解一点,即:任何数据实例化过程或者数据声明过程都是向系统申请内存空间,这些过程都是io,也即耗时操作。
再回到代码本身,在多线程情况下,当线程1运行完if not,但还没有执行实例化过程,此时如果CPU切换到线程2,线程2也执行到了if not,并完成了实例化过程,然后CPU再切换回了线程1,并继续执行了线程1的实例化过程,那么就是两个线程分别实例化了一次,也就不是单例了(这里还需要了解CPU的切换机制,在此处就不详细阐述了)
搞清楚上述方法无法满足多线程的原因之后,我们再来看如何去解决上述问题:
添加线程锁
import threading
class Singleton:
_instance_lock = threading.Lock()
def __init__(self, *args, **kwargs):
import time
time.sleep(5)
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
当我们添加了线程锁之后,就可以在多线程情况下实现单例了:
<__main__.Singleton object at 0x7f834719c310>
<__main__.Singleton object at 0x7f834719c310>
<__main__.Singleton object at 0x7f834719c310>
<__main__.Singleton object at 0x7f834719c310>
<__main__.Singleton object at 0x7f834719c310>
<__main__.Singleton object at 0x7f834719c310>
<__main__.Singleton object at 0x7f834719c310>
<__main__.Singleton object at 0x7f834719c310>
<__main__.Singleton object at 0x7f834719c310>
<__main__.Singleton object at 0x7f834719c310>
4.基于__new__方法实现(推荐)
实例化对象时,会先执行类的new方法(没有__new__方法时会默认执行object的__new__方法),然后再执行__init__方法初始化实例对象,那么我们可以通过定义__new__方法实现单例
import threading
class Singleton:
_instance_lock = threading.Lock()
def __init__(self, *args, **kwargs):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with _instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = object.__new__(cls)
return Singleton._instance
def task(arg):
obj = Singleton()
print(obj)
for i in range(10):
t = threading.Thread(target=task, args=[i,])
t.start()
执行结果:
<__main__.Singleton object at 0x7f9f37a9c350>
<__main__.Singleton object at 0x7f9f37a9c350>
<__main__.Singleton object at 0x7f9f37a9c350>
<__main__.Singleton object at 0x7f9f37a9c350>
<__main__.Singleton object at 0x7f9f37a9c350>
<__main__.Singleton object at 0x7f9f37a9c350>
<__main__.Singleton object at 0x7f9f37a9c350>
<__main__.Singleton object at 0x7f9f37a9c350>
<__main__.Singleton object at 0x7f9f37a9c350>
<__main__.Singleton object at 0x7f9f37a9c350>
5.基于metaclass(元类)实现
"""
关于元类(type):这里元类的概念,我们可以理解为创建类的类。当我们创建一个类时,会执行type的__init__()方法,使用类名+()创建类的实例化对像时,会调用元类type的__call__()方法。
关于__call__():该方法的功能类似于在类中重载()运算符,使得类的实例化对象可以像调用普通函数那样,以对象名+()的形式调用,普通类的对象基于类,类基于元类,都是如此。
"""
__call__的使用:
class Foo:
def __call__(self, *args, **kwargs):
print("执行__call__。。。")
obj = Foo()
print("创建实例化对象obj")
obj()
输出结果为:
创建实例化对象obj
执行__call__。。。
利用元类的__call__方法,我们可以这样实现单例:
import threading
class SingletonType(type):
_instance_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with SingletonType._instance_lock:
if not hasattr(cls, "_instance"):
cls._instance = super(SingletonType, cls).__call__(*args, **kwargs)
return cls._instance
class Foo(metaclass=SingletonType):
def __init__(self):
import time
time.sleep(5)
def task(arg):
obj = Foo()
print(obj)
for i in range(10):
t = threading.Thread(target=task, args=[i,])
t.start()
执行结果为:
<__main__.Foo object at 0x7ff725a9cf50>
<__main__.Foo object at 0x7ff725a9cf50>
<__main__.Foo object at 0x7ff725a9cf50>
<__main__.Foo object at 0x7ff725a9cf50>
<__main__.Foo object at 0x7ff725a9cf50>
<__main__.Foo object at 0x7ff725a9cf50>
<__main__.Foo object at 0x7ff725a9cf50>
<__main__.Foo object at 0x7ff725a9cf50>
<__main__.Foo object at 0x7ff725a9cf50>
<__main__.Foo object at 0x7ff725a9cf50>
参考链接:https://www.cnblogs.com/huchong/p/8244279.html
Python中实现单例的几种方式的更多相关文章
- Python中的单例设计
01. 单例设计模式 设计模式 设计模式 是 前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对 某一特定问题 的成熟的解决方案 使用 设计模式 是为了可重用代码.让代码更容易被他人理解.保 ...
- 转--python 中写单例
原文地址 原文地址2 Python中的单例模式的几种实现方式的及优化 阅读目录(Content) 单例模式 实现单例模式的几种方式 1.使用模块 2.使用装饰器 3.使用类 4.基于__new__方法 ...
- Objective-C和Swift实现单例的几种方式
在Swift开发中,我们对于跨类调用的变量常量,因为并没有OC中使用的全局头文件中写宏的形式,我们一般采用在类外定义全局变量/常量的形式来跨类调用.而问题在于目前写的项目需要在新添加的OC写的功能模块 ...
- python中的单例
使用__new__ 因为一个类每一次实例化的时候,都会走它的__new__方法.所以我们可以使用__new__来控制实例的创建过程,代码如下: class Single: instance = Non ...
- .NET Core中延迟单例另一种写法【.NET Core和.NET Framework的beforefieldinit差异】
1.BeforeFieldInit是什么 前段时间在反编译代码时无意间看到在类中有一个BeforeFieldInit特性,处于好奇的心态查了查这个特性,发现这是一个关于字段初始化时间的特性[提前初始化 ...
- Python中的单例设计模式
1)设计模式: 是前人工作的总结和提炼.通常,被人们广泛流传的设计模式. 某一问题的特定解决方案,使用设计模式是为了可重用代码,是代码更容易被人理解, 增加代码的可用性. 2)单例设计模式: ...
- swift实现单例的四种方式
单例模式 单例模式是设计模式中最简单的一种,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象. 当你只需要一个实例的时候需要使用单例 ...
- Java实现单例的5种方式
1. 什么是单例模式 单例模式指的是在应用整个生命周期内只能存在一个实例.单例模式是一种被广泛使用的设计模式.他有很多好处,能够避免实例对象的重复创建,减少创建实例的系统开销,节省内存. 2. 单例模 ...
- python 中增加css样式的三种方式
增加css样式的三种方式: <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...
- python中获取文件路径的几种方式
# 如果执行文件为E:\aa\bb\aa.py 1.获取当前路径 current_path11 = os.path.abspath(__file__) current_path12 = os.path ...
随机推荐
- @Async异步注解的使用
@Async 简介 使用spring快速开启异步执行服务的注解 应用场景 同步:同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果. 异步: 异步调用则是只是发送了调用的指令,调用者无需等 ...
- 监控室NTP/GPS同步时钟解决方案
深圳市立显电子有限公司,专业LED时钟生产厂家!--------[点击进入] 车站.机场.学校等场所监控室布置要求: 1.宜选择建筑物中环境噪声较小的声场所.如车站票务中心后台.机场保安值班室. ...
- dpkt 简单应用
import dpktfrom dpkt.utils import mac_to_str,inet_to_strcap=f'D:/test_pacp/6.pcap'with open(cap,'rb' ...
- ajax的简单应用
jsp文件: <%@ page import="java.text.SimpleDateFormat" %><%@ page import="java. ...
- MySQL -my.cnf配置文件优化
# [mysqld] datadir=/var/lib/mysql #socket=/var/lib/mysql/mysql.sock user=mysql ### 设置主从的时候的唯一ID 每台主机 ...
- 1005.Django自定义过滤器及标签
一.关于自定义 自定义的引入 内置函数--------->自定义函数 内置模块--------->自定义模板 内置过滤器------>自定义过滤器 内置标签---------> ...
- install package within python
import os os.system("pip install numpy") import subprocess subprocess.call(['pip3', 'insta ...
- ORACLE触发器:插入数据时,对其中的一个字段进行默认赋值
Create trigger t_datebefore insertbegin:new.sj = to_char(sysdate,'yyyy-MM-dd HH:mm:ss')end
- layui 手册
https://layui.yii666.com/doc/modules/layer.html
- loadrunner写webservice接口
先用soupUI调试 fiddler抓包 然后再写: web_custom_request("createSoapOrder", "URL=http:/ ...