视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Python设计模式之单例模式实例
2020-11-27 14:30:20 责编:小采
文档


注:使用的是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
395786
395786
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'

下载本文
显示全文
专题