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实现下载网易云音乐的高清MV
Mar 16 Python
python实现根据月份和日期得到星座的方法
Mar 27 Python
用Python的Django框架编写从Google Adsense中获得报表的应用
Apr 17 Python
Python的Django框架可适配的各种数据库介绍
Jul 15 Python
Pycharm学习教程(5) Python快捷键相关设置
May 03 Python
python 实现A*算法的示例代码
Aug 13 Python
利用ctypes获取numpy数组的指针方法
Feb 12 Python
深度学习入门之Pytorch 数据增强的实现
Feb 26 Python
Python select及selectors模块概念用法详解
Jun 22 Python
Python 找出英文单词列表(list)中最长单词链
Dec 14 Python
通过python-pptx模块操作ppt文件的方法
Dec 26 Python
Python学习开发之图形用户界面详解
Aug 23 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
PHP投票系统防刷票判断流程分析
2012/02/04 PHP
解析curl提交GET,POST,Cookie的简单方法
2013/06/29 PHP
YII路径的用法总结
2014/07/09 PHP
php mysql 封装类实例代码
2016/09/18 PHP
PHP中创建和编辑Excel表格的方法
2018/09/13 PHP
PHP+Apache实现二级域名之间共享cookie的方法
2019/07/24 PHP
利用jQuery操作对象数组的实现代码
2011/04/27 Javascript
jQuery EasyUI API 中文文档 - ValidateBox验证框
2011/10/06 Javascript
推荐10个超棒的jQuery工具提示插件
2011/10/11 Javascript
浅谈JavaScript之事件绑定
2013/07/08 Javascript
jQuery使用attr()方法同时设置多个属性值用法实例
2015/03/26 Javascript
jQuery简单实现input文本框内灰色提示文本效果的方法
2015/12/02 Javascript
jQuery实现form表单元素序列化为json对象的方法
2015/12/09 Javascript
浅谈javascript的call()、apply()、bind()的用法
2016/02/21 Javascript
基于jQuery实现瀑布流页面
2017/04/11 jQuery
JS实现图片放大镜插件详解
2017/11/06 Javascript
vue 组件高级用法实例详解
2018/04/11 Javascript
jquery.pagination.js分页使用教程
2018/10/23 jQuery
微信小程序与公众号实现数据互通的方法
2019/07/25 Javascript
BootstrapValidator实现表单验证功能
2019/11/08 Javascript
Python饼状图的绘制实例
2019/01/15 Python
python解析xml简单示例
2019/06/21 Python
python批量处理文件或文件夹
2020/07/28 Python
解决python-docx打包之后找不到default.docx的问题
2020/02/13 Python
Python语言编写智力问答小游戏功能
2020/10/13 Python
什么是"引用"?申明和使用"引用"要注意哪些问题?
2016/03/03 面试题
高级人员简历的自我评价分享
2013/11/03 职场文书
四年的大学生生活自我评价
2013/12/09 职场文书
英语专业个人求职信范文
2014/02/01 职场文书
新学期开学标语
2014/06/30 职场文书
2014年信贷员工作总结
2014/11/18 职场文书
2015年语文教学工作总结
2015/05/25 职场文书
运动会加油稿30字
2015/07/21 职场文书
小学同学聚会感言
2015/07/30 职场文书
公安忠诚教育心得体会
2016/01/23 职场文书
使用scrapy实现增量式爬取方式
2022/06/21 Python