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实现简易版的Web服务器(推荐)
Jan 29 Python
Python实现的redis分布式锁功能示例
May 29 Python
Python图像处理之图像的读取、显示与保存操作【测试可用】
Jan 04 Python
python matplotlib画图库学习绘制常用的图
Mar 19 Python
Python2.7版os.path.isdir中文路径返回false的解决方法
Jun 21 Python
python Django 创建应用过程图示详解
Jul 29 Python
django解决订单并发问题【推荐】
Jul 31 Python
ipad上运行python的方法步骤
Oct 12 Python
Django的CVB实例详解
Feb 10 Python
python3.6连接mysql数据库及增删改查操作详解
Feb 10 Python
Windows下PyCharm配置Anaconda环境(超详细教程)
Jul 31 Python
python反扒机制的5种解决方法
Feb 06 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
自己做矿石收音机
2021/03/02 无线电
php+ajax实现仿百度查询下拉内容功能示例
2017/10/20 PHP
JavaScript 输入框内容格式验证代码
2010/02/11 Javascript
菜鸟javascript基础资料整理2
2010/12/06 Javascript
Jquery提交表单 Form.js官方插件介绍
2012/03/01 Javascript
javascript的parseFloat()方法精度问题探讨
2013/11/26 Javascript
使用forever管理nodejs应用教程
2014/06/03 NodeJs
JS实现鼠标点击展开或隐藏表格行的方法
2015/03/03 Javascript
jQuery实现动画效果circle实例
2015/08/06 Javascript
jQuery实现动态表单验证时文本框抖动效果完整实例
2015/08/21 Javascript
基于JavaScript如何实现私有成员的语法特征及私有成员的实现方式
2015/10/28 Javascript
Jquery 全选反选实例代码
2015/11/19 Javascript
JavaScript快速切换繁体中文和简体中文的方法及网站支持简繁体切换的绝招
2016/03/07 Javascript
前端性能优化及技巧
2016/05/06 Javascript
微信小程序-详解数据缓存
2016/11/24 Javascript
在vue-cli项目中使用bootstrap的方法示例
2018/04/21 Javascript
使用node.js实现微信小程序实时聊天功能
2018/08/13 Javascript
vue.js 打包时出现空白页和路径错误问题及解决方法
2019/06/26 Javascript
Vue的属性、方法、生命周期实例代码详解
2019/09/17 Javascript
node解析修改nginx配置文件操作实例分析
2019/11/06 Javascript
Vue快速实现通用表单验证的方法
2020/02/24 Javascript
python实现C4.5决策树算法
2018/08/29 Python
解决项目pycharm能运行,在终端却无法运行的问题
2019/01/19 Python
python如何解析复杂sql,实现数据库和表的提取的实例剖析
2020/05/15 Python
迷你分体式空调:SoGoodToBuy
2018/08/07 全球购物
Watchshop德国:欧洲在线手表No.1
2019/06/20 全球购物
会计员岗位职责
2014/03/15 职场文书
省级优秀班集体申报材料
2014/05/25 职场文书
防灾减灾日活动总结
2014/08/26 职场文书
领导干部群众路线教育实践活动剖析材料
2014/10/10 职场文书
2016年“5.12”国际护士节活动总结
2016/04/06 职场文书
创业计划之特色精品店
2019/08/12 职场文书
导游词之贵州织金洞
2019/10/12 职场文书
关于Mybatis中SQL节点的深入解析
2022/03/19 Java/Android
mysql的Buffer Pool存储及原理
2022/04/02 MySQL
vue 自定义组件添加原生事件
2022/04/21 Vue.js