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 相关文章推荐
详解Django中的ifequal和ifnotequal标签使用
Jul 16 Python
Python的组合模式与责任链模式编程示例
Feb 02 Python
20招让你的Python飞起来!
Sep 27 Python
opencv python统计及绘制直方图的方法
Jan 21 Python
python查看文件大小和文件夹内容的方法
Jul 08 Python
Python的互斥锁与信号量详解
Sep 12 Python
Python常用模块logging——日志输出功能(示例代码)
Nov 20 Python
tensorflow使用range_input_producer多线程读取数据实例
Jan 20 Python
Django用内置方法实现简单搜索功能的方法
Dec 18 Python
安装python依赖包psycopg2来调用postgresql的操作
Jan 01 Python
用Python实现定时备份Mongodb数据并上传到FTP服务器
Jan 27 Python
matplotlib交互式数据光标mpldatacursor的实现
Feb 03 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面向对象全攻略 (十五) 多态的应用
2009/09/30 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(九)
2014/06/24 PHP
PHP会员找回密码功能的简单实现
2016/09/05 PHP
thinkphp实现把数据库中的列的值存到下拉框中的方法
2017/01/20 PHP
php求数组全排列,元素所有组合的方法总结
2017/03/14 PHP
PHP操作MySQL中BLOB字段的方法示例【存储文本与图片】
2017/09/15 PHP
深入浅析安装PhpStorm并激活的步骤详解
2020/09/17 PHP
Javascript技术技巧大全(五)
2007/01/22 Javascript
JS Canvas定时器模拟动态加载动画
2016/09/17 Javascript
详解Jquery EasyUI tree 的异步加载(遍历指定文件夹,根据文件夹内的文件生成tree)
2017/02/11 Javascript
使用Browserify来实现CommonJS的浏览器加载方法
2017/05/14 Javascript
基于openlayers4实现点的扩散效果
2020/08/17 Javascript
对vue里函数的调用顺序介绍
2018/03/17 Javascript
详解JavaScript中关于this指向的4种情况
2019/04/18 Javascript
js图片查看器插件用法示例
2019/06/22 Javascript
vue 项目软键盘回车触发搜索事件
2020/09/09 Javascript
解决vue打包 npm run build-test突然不动了的问题
2020/11/13 Javascript
基于JavaScript实现随机点名器
2021/02/25 Javascript
[56:56]VG vs LGD 2019国际邀请赛淘汰赛 胜者组 BO3 第一场 8.22
2019/09/05 DOTA
使用python加密自己的密码
2015/08/04 Python
完美解决Python 2.7不能正常使用pip install的问题
2018/06/12 Python
Python实现端口检测的方法
2018/07/24 Python
浅谈Python脚本开头及导包注释自动添加方法
2018/10/27 Python
Python3.5文件读与写操作经典实例详解
2019/05/01 Python
python为什么要安装到c盘
2020/07/20 Python
Python实现壁纸下载与轮换
2020/10/19 Python
css3实现3d旋转动画特效
2015/03/10 HTML / CSS
什么是SQL Server的确定性函数和不确定性函数
2016/08/04 面试题
国贸类专业毕业生的求职信分享
2013/12/08 职场文书
电厂厂长岗位职责
2014/01/02 职场文书
顶撞领导检讨书
2014/01/29 职场文书
决心书标准格式
2014/03/11 职场文书
考试保密承诺书
2014/08/30 职场文书
关于践行三严三实的心得体会
2016/01/05 职场文书
入党转正申请自我鉴定
2019/06/25 职场文书
用python开发一款操作MySQL的小工具
2021/05/12 Python