[python实现设计模式]-1. 单例模式
设计模式中,最简单的一个就是 “单例模式”, 那么首先,就实现一下单例模式。
那么根据个人的理解,很快就写出第一版。
# -*- coding: utf-8 -*-
class Singleton(object):
# 定义静态变量实例
__singleton = None
def __init__(self):
pass
@staticmethod
def get_instance():
if Singleton.__singleton is None:
Singleton.__singleton = Singleton()
return Singleton.__singleton
测试一下:
if __name__ == "__main__":
instance1 = Singleton.get_instance()
instance2 = Singleton.get_instance() print id(instance1)
print id(instance2)
liutrumpdeMacBook-Air:singleton trump$ python Singleton
4419778640
4419778640
看起来运行良好。但是其实,这里面有2个问题.
1. 这里类方法getinstance()用于获取单例,但是类本身也可以实例化,这样的方式其实并不符合单例模式的要求。
if __name__ == "__main__":
instance1 = Singleton.get_instance()
instance2 = Singleton.get_instance() instance3 = Singleton() print id(instance1)
print id(instance2)
print id(instance3) 执行结果:
liutrumpdeMacBook-Air:singleton trump$ python Singleton
4461824080
4461824080
4461824144
在c#或java的设计模式中,我们通常是通过私有化类的构造函数来杀死类本身的繁殖能力
然而python并没有访问限定强制约束, 那么怎么办呢?
这个后续再说.
但是这样做也有好处,代码简单,大家约定好这样子调用就行了。
但是最好在类的命名上也体现了出来这是一个单例类.
2. 这个单例类并不是线程安全的.
比如我写了如下的测试代码来测试它的线程安全性.
def test_singleton_in_thread():
print id(Singleton.get_instance()) if __name__ == "__main__":
idx = 0
while 1:
MyThread(test_singleton_in_thread, []).start()
idx += 1
if idx > 0X100:
break
很快,就发现这确实不是线程安全的....

关于问题1. 我们换个思路, 来谈一谈python里面的构造函数.(其实python里面并没有构造函数个概念,⊙﹏⊙, 叫习惯了而已)
python 里的__init__(self) 函数,之前一直被我认为是python类的构造函数 __del__(self), 一直被我认为是类的析构函数...
其实,这是不对滴.
这时候__new__(self)就要登场了.
我们看一下官方的介绍.
http://docs.python.org/2/reference/datamodel.html#object.new

这么鬼长,其实告诉我们了一个道理.
new是一个类方法,会创建对象时调用。而init方法是在创建完对象后调用,对当前对象的实例做一些一些初始化,无返回值。如果重写了new而在new里面没有调用init或者没有返回实例,那么init将不起作用。
我擦,类方法,又是什么鬼....
好吧,继续查下资料.
http://www.cnblogs.com/2gua/archive/2012/09/03/2668125.html
静态方法:无法访问类属性、实例属性,相当于一个相对独立的方法,跟类其实没什么关系,换个角度来讲,其实就是放在一个类的作用域里的函数而已。
尝试了写了一下.

然而报一个递归溢出......

查了一下. 借鉴了一下
http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python/31887#31887
# -*- coding: utf-8 -*-
class Singleton(object):
# 定义静态变量实例
__instance = None
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls.__instance
if __name__ == "__main__":
instance1 = Singleton()
instance2 = Singleton()
print id(instance1)
print id(instance2)
liutrumpdeMacBook-Air:singleton trump$ python Singleton3.py
4544985488
4544985488
这里不是很懂super的用法. 查了一下文档.

看起来是调用了object类的 __new__方法来构造出了我们需要的类.(类似于c#里的反射???,不知道python的解释器是如何实现的)
总之看起来是靠谱的。耶耶耶。
同样的, 这种写法依然不是线程安全的.
关于问题2.
为了保证在多线程下线程安全性。
我们在写单例模式时候, 通常使用双重检查锁定来检测实例是否存在。
为什么用double check, 请自行思考...
实现:
# -*- coding: utf-8 -*-
from MyThread import *
import threading Lock = threading.Lock() class Singleton(object): # 定义静态变量实例
__instance = None def __init__(self):
pass def __new__(cls, *args, **kwargs):
if not cls.__instance:
try:
Lock.acquire()
# double check
if not cls.__instance:
cls.__instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
finally:
Lock.release()
return cls.__instance def test_singleton_in_thread():
print id(Singleton()) if __name__ == "__main__":
idx = 0
while 1:
MyThread(test_singleton_in_thread, []).start()
idx += 1
if idx > 0X100:
break
运行结果:

证明是线程安全的. 欧耶.
上面的代码在单例模式中被称作,懒汉式单例.
还有一种称之为饿汉式单例.
遗憾的是,python下是没有办法实现的。
饿汉,太饿了, 一开始就把实例构造出来...是不是很形象.
贴个c#的代码,供参考.
解释: 声明一个私有static 成员实例并直接调用类默认静态构造函数实例化.
然后安插共有静态方法返回该实例.
使用CLR的静态成员只能在静态构造函数中构造并且只能构造一次的特性来实现了单例.
特别的直观和美观, 也保证了线程安全.
使用起来很方便.
但也有个弊端就是需要在类加载的时候就把实例给初始化出来.
当这个实例非常大或者构造很耗时的话此时的性能就会有影响.
通常情况,这种写法是使用最多的写法(反正我写的话肯定不想使用double check...)
class Singleton
{
private static Singleton instance = new EagerSingleton(); private Singleton() { } public static Singleton GetInstance()
{
return instance;
}
}
总结:
本文介绍了使用python来实现不能约束构造实例只能通过规约指定方法来实现的单例模式,并由此引申控制类的__new__函数来
约束类构造的实例。
本文并且讨论了多线程下的double check 的单例模式的实现。
本文并且讨论了单例模式的懒汉式实现以及饿汉式实现.
好,第一个最简单的设计模式的python实现就到这里。
to be continued.
[python实现设计模式]-1. 单例模式的更多相关文章
- Python:设计模式介绍--单例模式
单例模式 1.单例是只有一个实例2.通过静态字段+静态字段伪造出一个单例效果3.什么时候用:当所有实例中封装的数据相同时,创建单例模式(eg:连接池) 用单例模式创建连接池: class CP: __ ...
- Python与设计模式之单例模式
一.什么是单例 即单个实例,指的是同一个类实例化多次的结果指向同一个对象,用于节省内存空间 如果我们从配置文件中读取配置来进行实例化,在配置相同的情况下,就没必要重复产生对象浪费内存了 # setti ...
- python设计模式之单例模式(一)
前言 单例模式是创建模式中比较常见和常用的模式,在程序执行的整个生命周期只存在一个实例对象. 系列文章 python设计模式之单例模式(一) python设计模式之常用创建模式总结(二) python ...
- python设计模式之单例模式(二)
上次我们简单了解了一下什么是单例模式,今天我们继续探究.上次的内容点这 python设计模式之单例模式(一) 上次们讨论的是GoF的单例设计模式,该模式是指:一个类有且只有一个对象.通常我们需要的是让 ...
- python设计模式之单例模式(转)
设计模式之单例模式 单例设计模式是怎么来的?在面向对象的程序设计中,当业务并发量非常大时,那么就会出现重复创建相同的对象,每创建一个对象就会开辟一块内存空间,而这些对象其实是一模一样的,那么有没有办法 ...
- python_way,day8 面向对象【多态、成员--字段 方法 属性、成员修饰符、特殊成员、异常处理、设计模式之单例模式、模块:isinstance、issubclass】
python_way day8 一.面向对象三大特性: 多态 二.面向对象中的成员 字段.方法属性 三.成员修饰符 四.特殊成员 __init__.__doc__.__call__.__setitem ...
- 文成小盆友python-num8 面向对象中的成员,成员修饰符,特殊成员,异常处理,设计模式之单例模式
本节主要内容: 1.面向对象中的成员 2.成员修饰符 3.特殊成员 4.异常处理 5.设计模式之单例模式 一.面向对象中的成员(类的成员) 类的成员总共可以分为3大类,每类中有不同的分支. 1.总述, ...
- 由Python通过__new__实现单例模式,所想到的__new__和__init__方法的区别
之前通过读书,了解到在Python中可以通过__new__方法来实现单例模式,代码一个示例如下,我就有了几个疑问,什么是单例模式?__new__方法是用来做什么的?用__new__方法实现的单例模式, ...
- Python与设计模式之创建型模式及实战
用Python学习一下设计模式,如果很枯燥的话,就强行能使用的就用一下.设计模式参考Python与设计模式-途索 1. 单例模式 保证一个类仅有一个实例,并提供一个访问它的全局访问点. import ...
随机推荐
- C(++) Websocket实现扫码二维码登录---GoEasy
最近在做一个扫码登录功能,为此我还在网上搜了一下关于微信的扫描登录的实现方式.当这个功能完成了后,我决定将整个实现思路整理出来,方便自己以后查看也方便其他有类似需求的程序猿些. 要实现扫码登录我们需要 ...
- PHP常用数组函数介绍
array_splice() 删除数组中的指定元 array_splice(数组名,从前往后删的个数,new一个数组的大小);没有第三参数也就没有返数组,没有第三个参数时,第二个参数的意义为从前往后保 ...
- java.lang.NoClassDefFoundError: de.greenrobot.event.EventBus
转自:http://blog.csdn.net/jyp123123/article/details/52836905 java.lang.NoClassDefFoundError: de.greenr ...
- Exynos 4412
Exynos 4412采用了三星最新的32nm HKMG工艺,是三星的第一款四核处理器 1.启动 有时间再接着写……
- 2016HUAS_ACM暑假集训4K - 基础DP
我不知道怎么用DP,不过DFS挺好用.DFS思路很明显,搜索.记录,如果刚好找到总价值的一半就说明搜索成功. 题目大意:每组6个数,分别表示价值1到6的物品个数.现在问你能不能根据价值均分. Samp ...
- Java Concurrent之 AbstractQueuedSynchronizer
ReentrantLock/CountDownLatch/Semaphore/FutureTask/ThreadPoolExecutor的源码中都会包含一个静态的内部类Sync,它继承了Abstrac ...
- u-boot-2010.09移植(A)
第一阶段 1.开发环境 系统:centOS6.5 linux版本:2.6.32 交叉编译器:buildroot-2012.08 以上工具已经准备好,具体安装步骤不再 ...
- C#模拟键盘事件
public partial class Form1 : Form { public Form1() { InitializeComponent(); } [DllImport("USER3 ...
- DBA-mysql-init-password-5.7
1.Mysql5.7 Password; 查找临时密码:grep "A temporary password" /var/log/mysqld.log 修改临时密码:alter ...
- requests高级用法
会话对象 当你向同一主机发送多个请求时,session会重用底层的tcp连接,从而提升性能,同时session也会为所有请求保持 cookie. # _*_ coding: utf-8 _*_ imp ...