设计模式中,最简单的一个就是 “单例模式”, 那么首先,就实现一下单例模式。

那么根据个人的理解,很快就写出第一版。

# -*- 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

静态方法:无法访问类属性、实例属性,相当于一个相对独立的方法,跟类其实没什么关系,换个角度来讲,其实就是放在一个类的作用域里的函数而已。

类成员方法:可以访问类属性,无法访问实例属性。
类方法有类变量cls传入,从而可以用cls做一些相关的处理。并且有子类继承时,调用该类方法时,传入的类变量cls是子类,而非父类。 
 
了解了这些姿势以后,我们可以尝试通过改造类的__new__方法来给类进行计划生育了.
 

尝试了写了一下.

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

查了一下. 借鉴了一下

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. 单例模式的更多相关文章

  1. Python:设计模式介绍--单例模式

    单例模式 1.单例是只有一个实例2.通过静态字段+静态字段伪造出一个单例效果3.什么时候用:当所有实例中封装的数据相同时,创建单例模式(eg:连接池) 用单例模式创建连接池: class CP: __ ...

  2. Python与设计模式之单例模式

    一.什么是单例 即单个实例,指的是同一个类实例化多次的结果指向同一个对象,用于节省内存空间 如果我们从配置文件中读取配置来进行实例化,在配置相同的情况下,就没必要重复产生对象浪费内存了 # setti ...

  3. python设计模式之单例模式(一)

    前言 单例模式是创建模式中比较常见和常用的模式,在程序执行的整个生命周期只存在一个实例对象. 系列文章 python设计模式之单例模式(一) python设计模式之常用创建模式总结(二) python ...

  4. python设计模式之单例模式(二)

    上次我们简单了解了一下什么是单例模式,今天我们继续探究.上次的内容点这 python设计模式之单例模式(一) 上次们讨论的是GoF的单例设计模式,该模式是指:一个类有且只有一个对象.通常我们需要的是让 ...

  5. python设计模式之单例模式(转)

    设计模式之单例模式 单例设计模式是怎么来的?在面向对象的程序设计中,当业务并发量非常大时,那么就会出现重复创建相同的对象,每创建一个对象就会开辟一块内存空间,而这些对象其实是一模一样的,那么有没有办法 ...

  6. python_way,day8 面向对象【多态、成员--字段 方法 属性、成员修饰符、特殊成员、异常处理、设计模式之单例模式、模块:isinstance、issubclass】

    python_way day8 一.面向对象三大特性: 多态 二.面向对象中的成员 字段.方法属性 三.成员修饰符 四.特殊成员 __init__.__doc__.__call__.__setitem ...

  7. 文成小盆友python-num8 面向对象中的成员,成员修饰符,特殊成员,异常处理,设计模式之单例模式

    本节主要内容: 1.面向对象中的成员 2.成员修饰符 3.特殊成员 4.异常处理 5.设计模式之单例模式 一.面向对象中的成员(类的成员) 类的成员总共可以分为3大类,每类中有不同的分支. 1.总述, ...

  8. 由Python通过__new__实现单例模式,所想到的__new__和__init__方法的区别

    之前通过读书,了解到在Python中可以通过__new__方法来实现单例模式,代码一个示例如下,我就有了几个疑问,什么是单例模式?__new__方法是用来做什么的?用__new__方法实现的单例模式, ...

  9. Python与设计模式之创建型模式及实战

    用Python学习一下设计模式,如果很枯燥的话,就强行能使用的就用一下.设计模式参考Python与设计模式-途索 1. 单例模式 保证一个类仅有一个实例,并提供一个访问它的全局访问点. import ...

随机推荐

  1. js 获取当前焦点所在的元素、给元素和input控件添加键盘监听事件、添加页面级的键盘监听事件

    页面级的键盘监听事件 document.onkeydown = function (event) { var e = event || window.event || arguments.callee ...

  2. UML和UP简介(转载)

    UML(统一建模语言,Unified Modeling Language)是用于系统的可视化建模语言.  UP(统一过程,Unified Process)是通用的软件开发过程. 很多人或书籍过大的夸大 ...

  3. css布局列表,自适应

    关于并列的三列布局结构,从左至右依次为 A, B, C, 宽度分别为180px, 600px, 180px.要求在不改变 HTML 结构的情况下用CSS实现:ABC,CBA,BAC 三种布局及在CBA ...

  4. EF Core CodeFirst实践 ( 使用MS SqlServer)

    这里使用 MS SQLSERVER ,网上大多使用 SQLite 先来一个CodeFirst 新建项目 这里我们选择  ASP.NET Core Web Application (.NET Core) ...

  5. CentOS6.5上Oracle11gR2静默安装

    一.环境准备环境 操作系统:CentOS release 6.5 (Final) 内核版本:2.6.32-431.el6.x86_64 物理内存:2G(必须大于1G) swap分区:3G(必须大于3G ...

  6. Kindle Unlimited上的技术书籍

            直达链接:Kindle Unlimited         前不久,亚马逊在中国也推出了电子书包月服务.消息不灵通的我过了好久才看到这个消息,随后第一时间上官网查看具体情况.      ...

  7. js代码实现下拉菜单

    效果 js代码: <script type="text/javascript"> function ShowSub(li) {//函数定义 var subMenu = ...

  8. 获取应用程序信息.h

    ////  获取应用程序信息.h//  IOS笔记// 一般会用来判断是否有新版本.是否需要强制更新 iOS的版本号,一个叫做Version,一个叫做Build,这两个值都可以在Xcode 中选中ta ...

  9. Combination Sum II

    public class Solution { public List<List<Integer>> combinationSum2(int[] candidates, int ...

  10. Quartus II 增量编译

    在开发阶段,经常需要改代码,而且往往只改局部代码,但是编译的时候,通常会全部重新编译,这会很浪费时间,使得开发效率大大降低.那么有没有一种方法能够降低不必要的编译时间呢?通过查询Quartus II ...