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 当前全局变量和入口参数的所有属性
Jul 01 Python
python简单线程和协程学习心得(分享)
Jun 14 Python
Ubuntu安装Jupyter Notebook教程
Oct 18 Python
基于Python中单例模式的几种实现方式及优化详解
Jan 09 Python
python中(str,list,tuple)基础知识汇总
Feb 20 Python
Python Django中间件,中间件函数,全局异常处理操作示例
Nov 08 Python
python-OpenCV 实现将数组转换成灰度图和彩图
Jan 09 Python
python等差数列求和公式前 100 项的和实例
Feb 25 Python
Python如何使用turtle库绘制图形
Feb 26 Python
如何使用PyCharm将代码上传到GitHub上(图文详解)
Apr 27 Python
python字典通过值反查键的实现(简洁写法)
Sep 30 Python
python 获取字典键值对的实现
Nov 12 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/01 无线电
初学者入门:细述PHP4的核心Zend
2006/09/05 PHP
对javascript和select部件的结合运用
2006/10/09 PHP
微信支付开发教程(一)微信支付URL配置
2014/05/28 PHP
php获取POST数据的三种方法实例详解
2016/12/20 PHP
详解PHP5.6.30与Apache2.4.x配置
2017/06/02 PHP
PHP设计模式之迭代器模式Iterator实例分析【对象行为型】
2020/04/26 PHP
JavaScript方法和技巧大全
2006/12/27 Javascript
javascript实现的动态文字变换
2007/07/28 Javascript
基于jquery自己写tab滑动门(通用版)
2012/10/30 Javascript
AngularJS入门教程之表格实例详解
2016/07/27 Javascript
jquery 属性选择器(匹配具有指定属性的元素)
2016/09/06 Javascript
JavaScript编写一个简易购物车功能
2016/09/17 Javascript
使用Angular.js实现简单的购物车功能
2016/11/21 Javascript
JavaScript运动框架 多值运动(四)
2017/05/18 Javascript
angular实现图片懒加载实例代码
2017/06/08 Javascript
微信小程序商品到详情的实现
2017/06/27 Javascript
nodejs 子进程正确的打开方式
2017/07/03 NodeJs
AngularJS中controller控制器继承的使用方法
2017/11/03 Javascript
浅谈VUE防抖与节流的最佳解决方案(函数式组件)
2019/05/22 Javascript
微信小程序实现打卡签到页面
2020/09/21 Javascript
Vue通过阿里云oss的url连接直接下载文件并修改文件名的方法
2020/12/25 Vue.js
[01:57]2018年度DOTA2最具潜力解说-完美盛典
2018/12/16 DOTA
python 自动提交和抓取网页
2009/07/13 Python
在ironpython中利用装饰器执行SQL操作的例子
2015/05/02 Python
Python自定义线程类简单示例
2018/03/23 Python
python matplotlib画图库学习绘制常用的图
2019/03/19 Python
Pandas实现一列数据分隔为两列
2020/05/18 Python
python实现逢七拍腿小游戏的思路详解
2020/05/26 Python
Django ORM判断查询结果是否为空,判断django中的orm为空实例
2020/07/09 Python
Python趣味实例,实现一个简单的抽奖刮刮卡
2020/07/18 Python
酒店前厅员工辞职信
2014/01/08 职场文书
集体婚礼证婚词
2014/01/13 职场文书
2015年元旦文艺晚会总结(学院)
2014/11/28 职场文书
关于教师节的广播稿
2015/08/19 职场文书
SQL Server2019数据库之简单子查询的具有方法
2021/04/27 SQL Server