[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 ...
随机推荐
- 腾讯优测优分享 | Android适配中的一些特殊情况小结
腾讯优测是专业的自动化测试平台,提供全面兼容适配测试,远程真机租用等多维度的测试服务! 作为一名"艰苦卓绝"的软件工程师,我在开发路上经常被各种奇葩情况虐的体无完肤...今天就想与 ...
- metagenome 简介
宏基因组 ( Metagenome)(也称微生物环境基因组 Microbial Environmental Genome, 或元基因组) .是由 Handelsman 等 1998 年提出的新名词, ...
- 最短路径问题——floyd算法
floyd算法和之前讲的bellman算法.dijkstra算法最大的不同在于它所处理的终于不再是单源问题了,floyd可以解决任何点到点之间的最短路径问题,个人觉得floyd是最简单最好用的一种算法 ...
- html的基础标签
完整的网页由html嵌套 head.body构成 实例: <!DOCTYPE html><html lang="en"> <head> < ...
- HTML CSS中比较重要的
在网页中有了HTML和CSS之后,我们还需要学会布局,我们可以将整个网页看做是一个DIV,然后将所有内容放入到这个DIV中. 内容中的每一块我们都可以用DIV包起来,我们将这个DIV看做一个盒子,然后 ...
- WebLogic 12c控制台上传获取webshell
WebLogic 默认端口7001,一般可以通过这样来访问 http://10.9.1.1:7001/console 控制台 通过弱口令weblogic/weblogic登录控制台,下一步获取如何上传 ...
- iOS NSTimer使用详解 开启、关闭、移除
定时器定时器详解ios定时器关闭定时器NSTimer 一,要使用一个定时器首先要定义一个定时器: @property (strong, nonatomic) NSTimer *myTimer;//定时 ...
- AFNetwork ATS 网络层改造
最近一直做项目的ATS改造,期间遇到了种种问题,各种坑都记录下来, 比如iOS版本.afnetwork版本.证书(是否为自签证书).域名验证.TLS版本等等,我们项目更复杂,还使用了域名到IP映射的路 ...
- ubuntu 更换系统语言,Change System Language
1.打开设置,打开“Language Support”. 2.如果列表中没有你的语言,点击“Install/Remove Language”,下拉选择你的语言,点击“Apply Changes”. 3 ...
- bzoj1553: XOR网络
Description 计算给定范围内有多少种输入可以使输出为1. 我们假设3 < n < 100, 3 < m < 3000,而且网络中的门是用1到m之间的数任意编号的. ...