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中Request对象的相关用法
Jul 17 Python
Pandas读取MySQL数据到DataFrame的方法
Jul 25 Python
win8.1安装Python 2.7版环境图文详解
Jul 01 Python
在python中画正态分布图像的实例
Jul 08 Python
wxPython实现分隔窗口
Nov 19 Python
python装饰器代替set get方法实例
Dec 19 Python
python numpy库np.percentile用法说明
Jun 08 Python
python要安装在哪个盘
Jun 15 Python
python 如何调用 dubbo 接口
Sep 24 Python
实例详解Python的进程,线程和协程
Mar 13 Python
python 判断字符串当中是否包含字符(str.contain)
Jun 01 Python
Python sklearn分类决策树方法详解
Sep 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
深入了解 register_globals (附register_globals=off 网站打不开的解决方法)
2012/06/27 PHP
PHP计算2点经纬度之间的距离代码
2013/08/12 PHP
php创建sprite
2014/02/11 PHP
thinkphp3查询mssql数据库乱码解决方法分享
2014/02/11 PHP
PHP高并发和大流量解决方案整理
2019/12/24 PHP
javascript实现瀑布流自适应遇到的问题及解决方案
2015/01/28 Javascript
JavaScript将字符串转换为整数的方法
2015/04/14 Javascript
jquery实现浮动的侧栏实例
2015/06/25 Javascript
js判断上传文件后缀名是否合法
2016/01/28 Javascript
jQuery Easyui datagrid/treegrid 清空数据
2016/07/09 Javascript
JS 动态判断PC和手机浏览器实现代码
2016/09/21 Javascript
react开发教程之React 组件之间的通信方式
2017/08/12 Javascript
实例分析vue循环列表动态数据的处理方法
2018/09/28 Javascript
微信小程序出现wx.getLocation再次授权问题的解决方法分析
2019/01/16 Javascript
灵活使用console让js调试更简单的方法步骤
2019/04/23 Javascript
Vue 使用Props属性实现父子组件的动态传值详解
2019/11/13 Javascript
浅谈Vue SSR中的Bundle的具有使用
2019/11/21 Javascript
javascript实现前端input密码输入强度验证
2020/06/24 Javascript
[04:12]第二届DOTA2亚洲邀请赛选手传记-Newbee.Sccc
2017/04/03 DOTA
Python入门篇之编程习惯与特点
2014/10/17 Python
使用C语言来扩展Python程序和Zope服务器的教程
2015/04/14 Python
python中的字典操作及字典函数
2018/01/03 Python
pandas DataFrame数据转为list的方法
2018/04/11 Python
django 实现电子支付功能的示例代码
2018/07/25 Python
Python编程深度学习绘图库之matplotlib
2018/12/28 Python
python实现支付宝转账接口
2019/05/07 Python
python进阶之自定义可迭代的类
2019/08/20 Python
python KNN算法实现鸢尾花数据集分类
2019/10/24 Python
Python环境管理virtualenv&virtualenvwrapper的配置详解
2020/07/01 Python
使用CSS3制作一个简单的Chrome模拟器
2015/07/15 HTML / CSS
网上常见的一份Linux面试题(多项选择部分)
2015/02/07 面试题
个人银行贷款担保书
2014/04/01 职场文书
幼师大班个人总结
2015/02/13 职场文书
2016抗战胜利71周年红领巾广播稿
2015/12/18 职场文书
你有一份《诚信考试承诺书》待领取
2019/11/13 职场文书
Python实现学生管理系统(面向对象版)
2021/06/24 Python