Python 单例模式的几种实现方式
单例模式的几种实现方式
先来看几个魔法方法的简单运用:__new__, __init__, __call__。
class A(object):
def __init__(self, x):
print('x in __init__', x)
def __new__(cls, y): # 它只取下 cls 参数,并把其他参数传给 __init__
print('y in __new__', y)
return super(A, cls).__new__(cls)
def __call__(self, z): # 允许一个类的实例像函数一样被调用
print('z in __call__', z)
A('123')('abc') # 相当于先 a = A('123'), 再 a('abc')
# y in __new__ 123
# x in __init__ 123
# z in __call__ abc
1._new_(cls, *args, **kw) 方法实现
__new__ 构造方法至少需要一个 cls 参数,实例化时,解释器会自动填入;
需要注意的是,new 方法中调用 new 方法时不要再调用自己的 new 方法,会报【超出最大递归深度】错误;要调用父类的 new 方法(默认调用)。
class Singleton(object):
_instance = None # 新建一个类属性:需要使用类名前缀来访问
def __new__(cls, *args, **kw): # 创建实例时,判断是否已经存在,存在,返回,不存在,创建
if cls._instance is None:
cls._instance = object.__new__(cls, *args, **kw) # 不要调用自己的new方法, 即: cls.__new__(), 会无限递归的;
return cls._instance # 返回实例对象
def __init__(self):
pass
sing1 = Singleton()
sing2 = Singleton()
sing1 is sing2 # true
"""
若 _instance = {}, 则
if cls not in cls._instance:
cls._instance[cls] = object.__new__(cls, *args, **kw)
"""
2.函数装饰器实现:实例化前先调用这个装饰器返回的 inner() 函数,再返回实例
用不可变的 类地址 作为键,其 实例 作为值,每次创造实例时,首先判断该类是否存在实例,存在,直接返回该实例即可,否则新建一个实例并存放在字典中。
def singleton2(cls):
_instance = {} # 新建空字典; 不要_instance = None, 否则 inner 函数中赋值时,_instance 只会在函数作用域搜索,判断时会报错;
def inner(): # 判断是否已有实例,如无,则新建一个实例并返回
if cls not in _instance:
_instance[cls] = cls()
return _instance[cls] # 返回的是实例对象
return inner
@singleton2
class Cls():
def __init__(self):
pass # 可以照常添加属性和方法
cls1 = Cls()
cls2 = Cls()
cls1 is cls2 # True
3.类装饰器实现:类装饰器可以直接依靠类内部的__call__方法来实现
Python 中,凡是可以将 () 直接应用到自身并执行,都称为可调用对象。可调用对象包括自定义的函数、Python 内置函数以及类实例对象。
__call__ 方法可以使类实例对象可以像调用普通函数那样,以 “对象名()” 的形式使用;此方法会在实例作为一个函数被 “调用” 时被调用;
如果定义了此方法,则 x(arg1, arg2, ...) 就相当于 x.__call__(arg1, arg2, ...) 的快捷方式。只要实现了__call__方法的对象都是可被调用对象。
class Singleton3(object): # 自定义类装饰器
def __init__(self, cls): # 赋初值
self.cls = cls
self.instance = {}
def __call__(self): # 调用类装饰器时, 判断是否已存在
if self.cls not in self.instance:
self.instance[self.cls] = self.cls()
return self.instance[self.cls] # 返回实例对象
@Singleton3
class Cls2(object):
def __init__(self):
pass
cls3 = Cls2()
cls4 = Cls2()
cls3 is cls4 # True
class Cls3():
pass
Cls33 = Singleton3(Cls3) # Cls3 传给 __init__ 了;
cls5 = Cls33() # “名称()” 可以理解为是 “名称.__call__()” 的简写;
cls6 = Cls33()
cls5 is cls6 # True
4.metaless 元类实现
元类->类->实例,简单来说,就是类是由元类创建的,type 是内置的元类,也可以自定义元类。
type(name, bases, dict):name 是类的名字,bases 是要继承的父类集合,dict 是这个类的属性。下面两条语句会创建相同的 type 对象:
class X: a = 1
X = type('X', (object,), dict(a=1)) # 动态的创建类对象,dict(a=1) 也可以直接用 {'a':1, 'func_name': func_name}
class Singleton4(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton4, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class Cls4(metaclass=Singleton4):
pass
cls1 = Cls4()
cls2 = Cls4()
cls1 is cls2 # True
5.import 实现
python 模块是天然的单例模式:需要使用实例的时候,在文件中导入即可使用,从而减少相关实例的创建;
模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码;
因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:
# my_singleton.py
class My_Singleton(object):
def foo(self):
print('My_Singleton')
mysingle = My_Singleton()
# other.py
from my_singleton import mysingle
mysingle.foo()
6.共享属性
创建实例时, 把所有实例的 __dict__ 都指向同一个字典,这样它们就会共享同一个属性,具有相同的属性和方法。
要查看对象中存储的所有值,可检查其 __dict__ 属性。如果要确定对象是由什么组成的,应研究模块 inspect。
注意:此时只是对象值相同,多个对象共享一个数据,依旧以最新的值为准,但不是同一个对象。
class Borg(object):
_state = {} # 共享属性字典
def __new__(cls, *args, **kw):
ob = super(Borg, cls).__new__(cls, *args, **kw)
ob.__dict__ = cls._state # 指向同一个字典
return ob
class MyClass2(Borg):
a = 1
应用场景简介
每个实例都会占用资源,而且实例初始化会影响性能,这个时候就可以考虑使用单例模式,它给我们带来的好处是只有一个实例占用资源,并且只需初始化一次;
当有同步需要的时候,可以通过一个实例来进行同步控制,比如对某个共享文件(如日志文件)的控制,对计数器的同步控制等,这种情况下由于只有一个实例,所以不用担心同步问题。
模块 logger 就是一个单例模式;Windows的资源管理器是一个单例模式;线程池,数据库连接池等资源池一般也用单例模式;网站计数器;游戏场景管理器;
游戏中需要有 “场景管理器” 这样一种东西,用来管理游戏场景的切换、资源载入、网络连接等等任务。
这个管理器需要有多种方法和属性,在代码中很多地方会被调用,且被调用的必须是同一个管理器,否则既容易产生冲突,也会浪费内存资源。
某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,
也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。
Python 单例模式的几种实现方式的更多相关文章
- python 单例模式的四种创建方式
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- JAVA中单例模式的几种实现方式
1 线程不安全的实现方法 首先介绍java中最基本的单例模式实现方式,我们可以在一些初级的java书中看到.这种实现方法不是线程安全的,所以在项目实践中如果涉及到线程安全就不会使用这种方式.但是如果不 ...
- python中的三种输入方式
python中的三种输入方式 python2.X python2.x中以下三个函数都支持: raw_input() input() sys.stdin.readline() raw_input( )将 ...
- Python中的单例模式的几种实现方式的优缺点及优化
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- Python中的单例模式的几种实现方式的及优化
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- python单例模式的几种实现方法
单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场. ...
- Python基础:Python运行的两种基本方式
完成Python的安装之后,我们可以开始编写Python代码以及运行Python程序了.我们来看一下运行Python具体有哪几种方式 1.REPL 所谓REPL即read.eva.print.loop ...
- Python 45 css三种引入方式以及优先级
一:css三种引入方式 三种方式为:行间式 | 内联式 | 外联式 行间式 1.在标签头部的style属性内 2.属性值满足的是css语法 3.属性值用key:value形式赋值,value具 ...
- CSIC_716_20191129【 单例模式 的五种实现方式】
单例模式 单例模式:在确定类中的属性和方法不变时,需要反复调用该类的情况. 让所有通过该类实例化出的对象,都指向同一个内存地址. 优点:节省内存空间. 单例模式有五种表现形式: 1.通过class ...
随机推荐
- GeoServer课程规划
"凡事豫则立,不豫则废." --西汉·戴圣<礼记·中庸> 为了做好GeoServer课程培训,需要拟定一个课程目录,对整个课程做一个宏观上的规划.有了这个规划,就有了目 ...
- C++ DLL注入工具完整源码
先上源码 #include "Inject_Main.h" #include "resource.h" #include <Windows.h> # ...
- 利用application在页面中显示访问次数
在jsp页面中实现. <%@ page language="java" contentType="text/html; charset=UTF-8" pa ...
- ApacheCN jQuery 译文集 20211121 更新
创建 jQueryMobile 移动应用 零.序言 一.jQueryMobile 原型制作 二.jQuery Mobile 网站 三.分析.长表单和前端验证 四.QR 码.地理位置.谷歌地图 API ...
- react组件中的类调用construcor、super方法你知道多少?
constructor:在类中作为一个钩子函数,有constructor钩子函数的时候,可以定义state,如果用户不定义state的话,有无constructor钩子函数没啥区别: super:
- 「LOJ 6373」NOIP2017 普及组题目大融合
NOIP2017 普及组题目大融合 每个读者需要有某个后缀的书,可以暴力map,复杂度\(o(9*nlog(n))\),也可以反串建trie树,复杂度\(o(9*n)\). 故可以求出需要的最少的RM ...
- 根据指定手绘图纸照片行政区划自定义绘制对应区域边界生成geoJOSN的解决方案
项目需求 指定某区域(非省市区县乡镇标准行政区划),做功能边界分区,实现Echarts地理坐标数据可视化展示. 提供信息 项目分析 要在Echarts上实现地理坐标可视化,必须使用geoJSON格式文 ...
- bom-client
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 服务器性能测试利器之sysbench
前言 sysbench是一个开源的.模块化的.跨平台的多线程性能测试工具,可以用来进行CPU.内存.磁盘I/O.线程.数据库的性能测试.sysbench是基于LuaJIT的可编写脚本的多线程基准测试工 ...
- scons: 使用 SCons 轻松建造程序
转载请注明来源:https://www.cnblogs.com/hookjc/ 在软件项目开发过程中,make 工具通常被用来建造程序.make 工具通过一个被称为 Makefile 的配置文件可以自 ...