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中用Decorator来简化元编程的教程
Apr 13 Python
简单介绍Python中的floor()方法
May 15 Python
详细讲解Python中的文件I/O操作
May 24 Python
举例讲解Python编程中对线程锁的使用
Jul 12 Python
Python实现多线程HTTP下载器示例
Feb 11 Python
Python实现可设置持续运行时间、线程数及时间间隔的多线程异步post请求功能
Jan 11 Python
Python实现网站表单提交和模板
Jan 15 Python
在python tkinter中Canvas实现进度条显示的方法
Jun 14 Python
python关于矩阵重复赋值覆盖问题的解决方法
Jul 19 Python
python如何实现不可变字典inmutabledict
Jan 08 Python
Django的ListView超详细用法(含分页paginate)
May 21 Python
详解Python函数print用法
Jun 18 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
评分9.0以上的动画电影,剧情除了经典还很燃
2020/03/04 日漫
使用PHP获取网络文件的实现代码
2010/01/01 PHP
file_get_contents获取不到网页内容的解决方法
2013/03/07 PHP
100行PHP代码实现socks5代理服务器
2016/04/28 PHP
thinkPHP框架对接支付宝即时到账接口回调操作示例
2016/11/14 PHP
php提交表单时保留多个空格及换行的文本样式的方法
2017/06/20 PHP
php制作圆形用户头像的实例_自定义封装类源代码
2017/09/18 PHP
jQuery实现 注册时选择阅读条款 左右移动
2013/04/11 Javascript
js函数setTimeout延迟执行的简单介绍
2013/07/17 Javascript
js获取ajax返回值代码
2014/04/30 Javascript
JavaScript中计算网页中某个元素的位置
2015/06/10 Javascript
纯js代码实现简单计算器
2015/12/02 Javascript
AngularJS入门教程之控制器详解
2016/07/27 Javascript
jQuery基于Ajax方式提交表单功能示例
2017/02/10 Javascript
使用vue与jquery实时监听用户输入状态的操作代码
2017/09/19 jQuery
[01:53]DOTA2超级联赛专访Zhou 五年职业青春成长
2013/05/29 DOTA
[03:08]迎霜节狂欢!2018年迎霜节珍藏Ⅰ一览
2018/12/25 DOTA
[01:27:30]LGD vs Newbee 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/19 DOTA
详解Python编程中对Monkey Patch猴子补丁开发方式的运用
2016/05/27 Python
Python随机数用法实例详解【基于random模块】
2017/04/18 Python
利用Python查看目录中的文件示例详解
2017/08/28 Python
Pandas DataFrame 取一行数据会得到Series的方法
2018/11/10 Python
Python3 导入上级目录中的模块实例
2019/02/16 Python
pytorch如何冻结某层参数的实现
2020/01/10 Python
python初步实现word2vec操作
2020/06/09 Python
Debenhams百货英国官方网站:Debenhams UK
2016/07/12 全球购物
有机童装:Toby Tiger
2018/05/23 全球购物
毕业生就业自荐信
2013/12/04 职场文书
文明寝室申报材料
2014/05/12 职场文书
关爱留守儿童标语
2014/06/18 职场文书
学生穿着不得体检讨书
2014/10/12 职场文书
敬业奉献模范事迹材料
2014/12/24 职场文书
工作简报范文
2015/07/21 职场文书
妇联2016年六一国际儿童节活动总结
2016/04/06 职场文书
Vue实现动态查询规则生成组件
2021/05/27 Vue.js
SpringBoot快速入门详解
2021/07/21 Java/Android