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 18 Python
Python 专题五 列表基础知识(二维list排序、获取下标和处理txt文本实例)
Mar 20 Python
Python获取当前公网ip并自动断开宽带连接实例代码
Jan 12 Python
python实战之实现excel读取、统计、写入的示例讲解
May 02 Python
pandas 使用均值填充缺失值列的小技巧分享
Jul 04 Python
解决Numpy中sum函数求和结果维度的问题
Dec 06 Python
Pytorch 中retain_graph的用法详解
Jan 07 Python
TensorFlow自定义损失函数来预测商品销售量
Feb 05 Python
利用python画出AUC曲线的实例
Feb 28 Python
如何基于pandas读取csv后合并两个股票
Sep 25 Python
在Windows下安装配置CPU版的PyTorch的方法
Apr 02 Python
python中print格式化输出的问题
Apr 16 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
在PHP3中实现SESSION的功能(一)
2006/10/09 PHP
PHP strtotime函数详解
2009/12/18 PHP
基于Discuz security.inc.php代码的深入分析
2013/06/03 PHP
PHP中的函数-- foreach()的用法详解
2013/06/24 PHP
JS 分号引起的一段调试问题
2009/06/18 Javascript
Dreamweaver jQuery智能提示插件,支持版本提示,支持1.6api
2011/07/31 Javascript
UI Events 用户界面事件
2012/06/27 Javascript
setTimeout函数兼容各主流浏览器运行执行效果实例
2013/06/13 Javascript
json数据与字符串的相互转化示例
2013/09/18 Javascript
JavaScript中数据结构与算法(四):串(BF)
2015/06/19 Javascript
jQuery三级下拉列表导航菜单代码分享
2020/04/15 Javascript
jQuery在ie6下无法设置select选中的解决方法详解
2016/09/20 Javascript
Bootstrap表单控件学习使用
2017/03/07 Javascript
基于代数方程库Algebra.js解二元一次方程功能示例
2017/06/09 Javascript
jQuery dateRangePicker插件使用方法详解
2017/07/28 jQuery
Vue项目中添加锁屏功能实现思路
2018/06/29 Javascript
三种Webpack打包方式(小结)
2018/09/19 Javascript
JavaScript页面倒计时功能完整示例
2019/05/15 Javascript
javascript设计模式 ? 状态模式原理与用法实例分析
2020/04/22 Javascript
JavaScript实现矩形块大小任意缩放
2020/08/25 Javascript
使用Python抓取模板之家的CSS模板
2015/03/16 Python
Python基于多线程操作数据库相关问题分析
2018/07/11 Python
Python日期时间模块datetime详解与Python 日期时间的比较,计算实例代码
2018/09/14 Python
Python实现常见的回文字符串算法
2018/11/14 Python
PyQt5 窗口切换与自定义对话框的实例
2019/06/20 Python
pygame实现贪吃蛇游戏(下)
2019/10/29 Python
基于Python+QT的gui程序开发实现
2020/07/03 Python
牵手50新加坡:专为黄金岁月的单身人士而设的交友网站
2020/08/16 全球购物
英国著名的美容护肤和护发产品购物网站:Lookfantastic
2020/11/23 全球购物
4s店机修工岗位职责
2013/12/20 职场文书
安全保证书范文
2014/04/29 职场文书
工作检讨书500字
2014/10/19 职场文书
2014年党风廉政工作总结
2014/12/03 职场文书
小学校长个人总结
2015/03/03 职场文书
自我推荐信格式模板
2015/03/24 职场文书
党纪处分决定书
2015/06/24 职场文书