[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 ...
随机推荐
- 通过BroadCast与service时时监听网络变化
首先需要一个service: 这里我定义了一个NetworkStateService,在这个service中我写了一个BroadcastReceiver用于监听网络状态发生改变的情况并在这个servi ...
- React(JSX语法)-----JSX属性
1. if you know all the propertities that you want to place on a component ahead of time,it is easy t ...
- case when then else end 的用法
case when then end 改语句的执行过程是:将case后面表达式的值与各when子句中的值进行比较,如果两者相等,则返回then后的表达式的值,然后跳出case语句,否则返回else子句 ...
- ZipArchive之C++编译和调用
由于要用到zip的解压,就上网下载了CZipArchive类的源码(还是2000年的),里面有个示例,稍微修改下,就能正常运行. 就高兴地把lib拿出来,放到项目中了.捣鼓了快一个下午了,死活编译不通 ...
- LeetCode-Sort Colors
Given an array with n objects colored red, white or blue, sort them so that objects of the same colo ...
- [llvm] Call the LLVM Jit from c program
stackoverflow: http://stackoverflow.com/questions/1838304/call-the-llvm-jit-from-c-program Another t ...
- TD Rigging Demo Reel 性感美女绑定展示
161455520158189 这是一个充满回忆的Demo,非常怀念之前的工作生活,也特别感谢我长春的老哥张总对我的帮助与指导,不光是工作中,在生活上也让我有很大的收获.这个一直都觉得做的不够好,也从 ...
- sql查询语句
//查询表的字段名和字段类型select column_name,data_type from information_schema.columns where table_name = '表名' / ...
- kvm
硬件,os,内核模块,用户空间工具,命令行具体参数,日志 [root@localhost ~]# yum install pciutils [root@localhost ~]# lscpu;lspc ...
- cuda-convnet windows8下编译
编译环境: windows8.1 Anaconda python2.7 Visual studio 2012 CUDA6.0 Pthread for windows Intel Math Kernel ...