Python设计模式之单例模式实例


Posted in Python onApril 26, 2014

注:使用的是Python 2.7。

一个简单实现

class Foo(object):
    __instance = None
    def __init__(self):
        pass
    @classmethod
    def getinstance(cls):
        if(cls.__instance == None):
            cls.__instance = Foo()
        return cls.__instance
if __name__ == '__main__':
    foo1 = Foo.getinstance()
    foo2 = Foo.getinstance()
    print id(foo1)
    print id(foo2)
    print id(Foo())

输出的前两个结果是相同的(id(foo1)与id(foo2)的值相同),第三个结果和前两个不同。这里类方法getinstance()用于获取单例,但是类本身也可以实例化,这样的方式其实并不符合单例模式的要求。但是这样做也有好处,代码简单,大家约定好这样子调用就行了。但是最好在类的命名上也体现了出来这是一个单例类,例如Foo_singleton。

换一个思路

先说一下init和new的区别:

class Foo(object):
    __instance = None
    def __init__(self):
        print 'init'
if __name__ == '__main__':
    foo = Foo()

运行结果是:
init

而下面的示例:
class Foo(object):
    __instance = None
    def __init__(self):
        print 'init'
    def __new__(cls, *args, **kwargs):
        print 'new'
if __name__ == '__main__':
    foo = Foo()

运行结果是:
new

new是一个类方法,会创建对象时调用。而init方法是在创建完对象后调用,对当前对象的实例做一些一些初始化,无返回值。如果重写了new而在new里面没有调用init或者没有返回实例,那么init将不起作用。以下内容引用自http://docs.python.org/2/reference/datamodel.html#object.new

If __new__() returns an instance of cls, then the new instance's __init__() method will be invoked like __init__(self[, ...]), where self is the new instance and the remaining arguments are the same as were passed to __new__().
If __new__() does not return an instance of cls, then the new instance's __init__() method will not be invoked.

这样做:
class Foo(object):
    __instance = None
    def __init__(self):
        print 'init'
    def __new__(cls, *args, **kwargs):
        print 'new'
        if cls.__instance == None:
            cls.__instance = cls.__new__(cls, *args, **kwargs)
        return cls.__instance
if __name__ == '__main__':
    foo = Foo()

    错误如下:

RuntimeError: maximum recursion depth exceeded in cmp

而这样也有一样的错误:

class Foo(object):
    __instance = None
    def __init__(self):
        if self.__class__.__instance == None:
            self.__class__.__instance = Foo()
        print 'init'
if __name__ == '__main__':
    foo = Foo()

该怎么做呢?

下面参考了http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python/31887#31887:

class Foo(object):
    __instance = None
    def __new__(cls, *args, **kwargs):
        print 'hhhhhhhhh'
        if not cls.__instance:
            cls.__instance = super(Foo, cls).__new__(cls, *args, **kwargs)
        return cls.__instance
    def hi(self):
        print 'hi, world'
        print 'hi, letian'
if __name__ == '__main__':
    foo1 = Foo()
    foo2 = Foo()
    print id(foo1)
    print id(foo2)
    print isinstance(foo1, object)
    print isinstance(foo1, Foo)
    foo1.hi()

运行结果:
hhhhhhhhh
hhhhhhhhh
39578896
39578896
True
True
hi, world
hi, letian

那么,到底发生了什么,我们先回顾一下super:
>>> print super.__doc__
super(type) -> unbound super object
super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type, type2) -> bound super object; requires issubclass(type2, type)
Typical use to call a cooperative superclass method:
class C(B):
    def meth(self, arg):
        super(C, self).meth(arg)

可以肯定上面的单例模式代码中的这一行代码:
cls.__instance = super(Foo, cls).__new__(cls, *args, **kwargs)

super(Foo, cls)是object,super(Foo, cls).new方法使用的是object的new方法。我们看一下object.new方法的作用:
>>> print object.__new__.__doc__
T.__new__(S, ...) -> a new object with type S, a subtype of T

如果是一个继承链

class Fo(object):
    def __new__(cls, *args, **kwargs):
        print 'hi, i am Fo'
        return  super(Fo, cls).__new__(cls, *args, **kwargs)
class Foo(Fo):
    __instance = None
    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            print Foo is cls
            print issubclass(cls, Fo)
            print issubclass(cls, object)
            cls.__instance = super(Foo, cls).__new__(cls, *args, **kwargs)
        return cls.__instance
    def hi(self):
        print 'hi, world'
if __name__ == '__main__':
    foo1 = Foo()
    foo1.hi()
    print isinstance(foo1, Foo)
    print isinstance(foo1, Fo)
    print isinstance(foo1, object)

运行结果如下:
True
True
True
hi, i am Fo
hi, world
True
True
True

如果如下定义Fo,也正常运行:
class Fo(object):
    pass

但是,若这样定义:
class Fo(object):
    def __new__(cls, *args, **kwargs):
        print 'hi, i am Fo'

运行时报错如下:
AttributeError: 'NoneType' object has no attribute 'hi'
Python 相关文章推荐
用Python写的图片蜘蛛人代码
Aug 27 Python
python实现带错误处理功能的远程文件读取方法
Apr 29 Python
基于随机梯度下降的矩阵分解推荐算法(python)
Aug 31 Python
将tensorflow.Variable中的某些元素取出组成一个新的矩阵示例
Jan 04 Python
python烟花效果的代码实例
Feb 25 Python
Python编程快速上手——疯狂填词程序实现方法分析
Feb 29 Python
基于python图像处理API的使用示例
Apr 03 Python
python 已知平行四边形三个点,求第四个点的案例
Apr 12 Python
python“静态”变量、实例变量与本地变量的声明示例
Nov 13 Python
python 三种方法实现对Excel表格的读写
Nov 19 Python
七个Python必备的GUI库
Apr 27 Python
python如何将mat文件转为png
Jul 15 Python
Python设计模式之观察者模式实例
Apr 26 #Python
Python设计模式之代理模式实例
Apr 26 #Python
python中的列表推导浅析
Apr 26 #Python
Python中的Numpy入门教程
Apr 26 #Python
Python中的map、reduce和filter浅析
Apr 26 #Python
Python实现的Kmeans++算法实例
Apr 26 #Python
爬山算法简介和Python实现实例
Apr 26 #Python
You might like
Zerg基本策略
2020/03/14 星际争霸
PHP+Redis链表解决高并发下商品超卖问题(实现原理及步骤)
2020/08/03 PHP
Add a Formatted Table to a Word Document
2007/06/15 Javascript
JQuery操作Select的Options的Bug(IE8兼容性视图模式)
2013/04/21 Javascript
JS实现可改变列宽的table实例
2013/07/02 Javascript
Jquery 动态循环输出表格具体方法
2013/11/23 Javascript
jQuery实现表格行上移下移和置顶的方法
2015/05/22 Javascript
jQuery实现鼠标滑过点击事件音效试听
2015/08/31 Javascript
详解js中构造流程图的核心技术JsPlumb
2015/12/08 Javascript
老生常谈原生JS执行环境与作用域
2016/11/22 Javascript
基于JavaScript实现熔岩灯效果导航菜单
2017/01/04 Javascript
jQuery ajax动态生成table功能示例
2017/06/14 jQuery
[48:52]DOTA2上海特级锦标赛A组小组赛#2 Secret VS CDEC第一局
2016/02/25 DOTA
[57:47]Fnatic vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
新手如何快速入门Python(菜鸟必看篇)
2017/06/10 Python
python删除不需要的python文件方法
2018/04/24 Python
python导入模块交叉引用的方法
2019/01/19 Python
对Python3中列表乘以某一个数的示例详解
2019/07/20 Python
pytorch程序异常后删除占用的显存操作
2020/01/13 Python
python实现五子棋游戏(pygame版)
2020/01/19 Python
在jupyter notebook 添加 conda 环境的操作详解
2020/04/10 Python
python异步Web框架sanic的实现
2020/04/27 Python
keras实现调用自己训练的模型,并去掉全连接层
2020/06/09 Python
Django如何批量创建Model
2020/09/01 Python
LocalStorage记住用户和密码功能
2017/07/24 HTML / CSS
碧欧泉美国官网:Biotherm美国
2016/08/31 全球购物
马来西亚网上美容店:Hermo.my
2017/11/25 全球购物
Bose美国官网:购买Bose耳机和音箱
2019/03/10 全球购物
领先的英国注册在线药房 :Simply Meds Online
2019/03/28 全球购物
北京RT科技有限公司.net工程师面试题
2013/02/15 面试题
GWT (Google Web Toolkit)有哪些主要的原件组成?
2015/06/08 面试题
男性健康日的活动方案
2014/08/18 职场文书
女儿满月酒致辞
2015/07/29 职场文书
初中语文教学研修日志
2015/11/13 职场文书
创业计划书之珠宝饰品
2019/08/26 职场文书
MyBatis-Plus 批量插入数据的操作方法
2021/09/25 Java/Android