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使用MySQLdb for Python操作数据库教程
Oct 11 Python
Python的SQLAlchemy框架使用入门
Apr 29 Python
PyQt 线程类 QThread使用详解
Jul 16 Python
Pandas DataFrame 取一行数据会得到Series的方法
Nov 10 Python
python实现图片识别汽车功能
Nov 30 Python
Python安装Flask环境及简单应用示例
May 03 Python
django中上传图片分页三级联动效果的实现代码
Aug 30 Python
python的等深分箱实例
Nov 22 Python
Python 将json序列化后的字符串转换成字典(推荐)
Jan 06 Python
python+opencv3生成一个自定义纯色图教程
Feb 19 Python
python如何建立全零数组
Jul 19 Python
Python解析微信dat文件的方法
Nov 30 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语法(5)
2006/10/09 PHP
Nginx服务器上安装并配置PHPMyAdmin的教程
2015/08/18 PHP
PHP getallheaders无法获取自定义头(headers)的问题
2016/03/23 PHP
详解PHP中cookie和session的区别及cookie和session用法小结
2016/06/12 PHP
laravel框架使用FormRequest进行表单验证,验证异常返回JSON操作示例
2020/02/18 PHP
jQuery 锚点跳转滚动条平滑滚动一句话代码
2010/04/30 Javascript
25个优雅的jQuery Tooltip插件推荐
2011/05/25 Javascript
Jquery Validate 正则表达式实用验证代码大全
2013/08/23 Javascript
jQuery实现的仿select功能代码
2015/08/19 Javascript
jQuery实现带渐显效果的人物多级关系图代码
2015/10/16 Javascript
用js实现放大镜的效果的简单实例
2016/05/23 Javascript
Vue.js每天必学之计算属性computed与$watch
2016/09/05 Javascript
JS常用知识点整理
2017/01/21 Javascript
JavaScript实现旋转轮播图
2020/08/18 Javascript
基于Vue的ajax公共方法(详解)
2018/01/20 Javascript
javascript和php使用ajax通信传递JSON的实例
2018/08/21 Javascript
利用hasOwnProperty给数组去重的面试题分享
2018/11/05 Javascript
jQuery中实现text()的方法
2019/04/04 jQuery
小程序实现长按保存图片的方法
2019/12/31 Javascript
[49:40]2018DOTA2亚洲邀请赛小组赛 A组加赛 TNC vs Newbee
2018/04/03 DOTA
[01:33:14]LGD vs VP Supermajor 败者组决赛 BO3 第二场 6.10
2018/07/04 DOTA
[01:47]2018年度DOTA2最具人气解说-完美盛典
2018/12/16 DOTA
python使用递归解决全排列数字示例
2014/02/11 Python
python实现sublime3的less编译插件示例
2014/04/27 Python
python基于windows平台锁定键盘输入的方法
2015/03/05 Python
Python入门之modf()方法的使用
2015/05/15 Python
Python可变参数用法实例分析
2017/04/02 Python
windows 下python+numpy安装实用教程
2017/12/23 Python
python3+PyQt5实现自定义分数滑块部件
2018/04/24 Python
Python命令行参数解析工具 docopt 安装和应用过程详解
2019/09/26 Python
使用pickle存储数据dump 和 load实例讲解
2019/12/30 Python
基于python实现简单C/S模式代码实例
2020/09/14 Python
指针和引用有什么区别
2013/01/13 面试题
中科软笔试题和面试题
2014/10/07 面试题
简单租房协议书
2014/10/21 职场文书
评奖评优个人先进事迹材料
2015/11/04 职场文书