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网络爬虫采集联想词示例
Feb 11 Python
在Python中操作字符串之replace()方法的使用
May 19 Python
python获取指定路径下所有指定后缀文件的方法
May 26 Python
Python中常用操作字符串的函数与方法总结
Feb 04 Python
PyTorch读取Cifar数据集并显示图片的实例讲解
Jul 27 Python
TensorFlow打印tensor值的实现方法
Jul 27 Python
Python字符串的全排列算法实例详解
Jan 07 Python
python根据时间获取周数代码实例
Sep 30 Python
Python threading.local代码实例及原理解析
Mar 16 Python
利用python实现后端写网页(flask框架)
Feb 28 Python
python编程学习使用管道Pipe编写优化代码
Nov 20 Python
实战Python爬虫爬取酷我音乐
Apr 11 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清除数组中所有字符串两端空格的方法
2014/10/20 PHP
PHP设计模式之工厂方法设计模式实例分析
2018/04/25 PHP
javascript 仿QQ滑动菜单效果代码
2010/09/03 Javascript
基于JQuery实现相同内容合并单元格的代码
2011/01/12 Javascript
nodejs教程之制作一个简单的文章发布系统
2014/11/21 NodeJs
javascript使用avalon绑定实现checkbox全选
2015/05/06 Javascript
js强制把网址设为默认首页
2015/09/29 Javascript
学JavaScript七大注意事项【必看】
2016/05/04 Javascript
利用JavaScript对中文(汉字)进行排序实例详解
2017/06/18 Javascript
javaScript手机号码校验工具类PhoneUtils详解
2017/12/08 Javascript
angular 实时监听input框value值的变化触发函数方法
2018/08/31 Javascript
微信小程序开发之路由切换页面重定向问题
2018/09/18 Javascript
如何使用electron-builder及electron-updater给项目配置自动更新
2018/12/24 Javascript
为什么要使用Vuex的介绍
2019/01/19 Javascript
JS中的算法与数据结构之字典(Dictionary)实例详解
2019/08/20 Javascript
使用JS来动态操作css的几种方法
2019/12/18 Javascript
jQuery实现移动端下拉展现新的内容回弹动画
2020/06/24 jQuery
jQuery 动态粒子效果示例代码
2020/07/07 jQuery
JavaScript array常用方法代码实例详解
2020/09/02 Javascript
vue点击按钮实现简单页面的切换
2020/09/08 Javascript
Vue父子组件传值的一些坑
2020/09/16 Javascript
Python通过matplotlib绘制动画简单实例
2017/12/13 Python
50行Python代码获取高考志愿信息的实现方法
2019/07/23 Python
TensorFlow-gpu和opencv安装详细教程
2020/06/30 Python
IE8下CSS3选择器nth-child() 不兼容问题的解决方法
2016/11/16 HTML / CSS
FirstCry阿联酋儿童和婴儿产品网上购物:FirstCry.ae
2021/02/22 全球购物
Java程序员面试90题
2013/10/19 面试题
艺术应用与设计个人的自我评价
2013/11/23 职场文书
师德师风建设方案
2014/05/08 职场文书
离婚协议书范本(通用篇)
2014/11/30 职场文书
讲座新闻稿
2015/07/18 职场文书
2016年中学清明节活动总结
2016/04/01 职场文书
关于考试抄袭的检讨书
2019/11/02 职场文书
python随机打印成绩排名表
2021/06/23 Python
go使用Gin框架利用阿里云实现短信验证码功能
2021/08/04 Golang
德劲DE1107指针试高灵敏度全波段收音机机评
2022/04/05 无线电