设计模式-单例-Python实现

单例是什么?

单例模式,也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。

维基百科-单例模式

简单来说,就是某种类,它有且就有一个实例。

在Python中怎么实现

重写__new__方法

__new__是类在创建时(不是实例化)时会调用的成员方法,其参数是这个类本身,即cls。这里我们使用hasattr方法来判断一个类有没有实例。如果没有就新建一个,有的话就返回当前的那个。这样就保证了这个类永远只会有一个实例。

# singleton
class Singleton(object):
    def __new__(cls):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

class MyClass(Singleton):
    a = 1


A = MyClass()
B = MyClass()

print (A is B)

装饰器实现

这个方法的核心思想就是将对象的实例用其他的容器保存下来,每次实例类的时候,装饰器会判断这个类是不是已经在容器中了。如果是,则直接返回容器中的实例,否则则新建一个实例返回并放入容器中。容器中最多只会有一个值。

# singleton
def singleton(cls):
    instances = {}
    def getinstance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return getinstance

@singleton
class MyClass():
    a = 1

A = MyClass()
B = MyClass()

print (A is B)

用list 也可以

# singleton
def singleton(cls):
    instances = []
    def getinstance(*args, **kwargs):
        if not instances:
           instances.append(cls(*args, **kwargs))
        return instances[0]
    return getinstance

@singleton
class MyClass():
    a = 1

A = MyClass()
B = MyClass()

#print (len(A))
print (A is B)

这样也可以

# singleton
instances = None
def singleton(cls):
    def getinstance(*args, **kwargs):
        global instances
        if not instances:
           instances = cls(*args, **kwargs)
        return instances
    return getinstance

@singleton
class MyClass():
    a = 1

A = MyClass()
B = MyClass()

#print (len(A))
print (A is B)

但是这样不行

# singleton
def singleton(cls):
    instance = None
    def getinstance(*args, **kwargs):
        if not instance:
           instance = cls(*args, **kwargs)
        return instance
    return getinstance

@singleton
class MyClass():
    a = 1

A = MyClass()
B = MyClass()

#print (len(A))
print (A is B)

为什么?因为这里构成了闭包,Python只会会把闭包中用到的值保存下来,但是你不能在闭包中对其进行修改。也就是说在这个例子里,你只能访问instance,但是不能对其赋值,否则会报错UnboundLocalError。我会在另外一篇关于作用域和闭包的文章中仔细讲一讲。

怎么改呢?一种就是用上面的两种方法,将它改成一个列表或者字典,我们不能对列表本身做修改,但是可以对列表中包含的对象做修改;另一种方法则是用关键词nonlocal:

# singleton
def singleton(cls):
    instance = None
    def getinstance(*args, **kwargs):
        nonlocal instance
        if not instance:
           instance = cls(*args, **kwargs)
        return instance
    return getinstance

@singleton
class MyClass():
    a = 1

A = MyClass()
B = MyClass()

#print (len(A))
print (A is B)

你可能感兴趣的:(设计模式-单例-Python实现)