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中hashlib模块用法示例
Oct 30 Python
python使用邻接矩阵构造图代码示例
Nov 10 Python
Python中单、双下划线的区别总结
Dec 01 Python
100行Python代码实现自动抢火车票(附源码)
Jan 11 Python
Python简单实现的代理服务器端口映射功能示例
Apr 08 Python
Python爬虫实战之12306抢票开源
Jan 24 Python
分享一个pycharm专业版安装的永久使用方法
Sep 24 Python
python 按钮点击关闭窗口的实现
Mar 04 Python
python如何导入依赖包
Jul 13 Python
Python3如何在服务器打印资产信息
Aug 27 Python
python代码实现猜拳小游戏
Nov 30 Python
弄清Pytorch显存的分配机制
Dec 10 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 SQL Injection with MySQL
2011/02/27 PHP
使用PHP Socket 编程模拟Http post和get请求
2014/11/25 PHP
项目中应用Redis+Php的场景
2016/05/22 PHP
Prototype String对象 学习
2009/07/19 Javascript
JS合并数组的几种方法及优劣比较
2014/09/19 Javascript
javascript中alert()与console.log()的区别
2015/08/26 Javascript
javascript实现简单计算器效果【推荐】
2016/04/19 Javascript
Vue2.0实现购物车功能
2017/06/05 Javascript
详解vue-router2.0动态路由获取参数
2017/06/14 Javascript
详解webpack和webpack-simple中如何引入css文件
2017/06/28 Javascript
原生JS实现的雪花飘落动画效果
2018/05/03 Javascript
详解Koa中更方便简单发送响应的方式
2018/07/20 Javascript
VUE DOM加载后执行自定义事件的方法
2018/09/07 Javascript
Vuex 使用 v-model 配合 state的方法
2018/11/13 Javascript
JavaScript实现星级评价效果
2019/05/17 Javascript
vue中使用带隐藏文本信息的图片、图片水印的方法
2020/04/24 Javascript
详解element-ui 表单校验 Rules 配置 常用黑科技
2020/07/11 Javascript
[01:03:51]2018DOTA2亚洲邀请赛 4.7 淘汰赛 VP vs LGD 第三场
2018/04/09 DOTA
python判断一个集合是否包含了另外一个集合中所有项的方法
2015/06/30 Python
Python解析Excle文件中的数据方法
2018/10/23 Python
python3实现高效的端口扫描
2019/08/31 Python
Python协程 yield与协程greenlet简单用法示例
2019/11/22 Python
世界上最大的在线学习和教学市场:Udemy
2017/11/08 全球购物
int和Integer有什么区别
2013/05/25 面试题
通信工程毕业生求职信
2013/11/16 职场文书
企划主管岗位职责
2013/12/12 职场文书
财政专业求职信范文
2014/02/19 职场文书
小学优秀教育工作者事迹材料
2014/05/09 职场文书
汽车运用工程专业求职信
2014/06/18 职场文书
学习教师法的心得体会
2014/09/03 职场文书
单位工作证明范文
2014/09/14 职场文书
房屋维修申请报告
2015/05/18 职场文书
2015年行政管理人员工作总结
2015/10/15 职场文书
学生会副主席竞选稿
2015/11/19 职场文书
MySQL官方导出工具mysqlpump的使用
2021/05/21 MySQL
python编写五子棋游戏
2021/05/25 Python