六、单例模式

扩展:__call__ 

只要它含有__call__属性,这个对象就是callable的,对象后就可以加()进行调用

# 含有__call__属性的,是可调用的,能够加括号
# 反之没有__call__属性,就是不可调用的,不能加括号
print(dir(lambda x, y: x+y)) # ['__annotations__', '__call__'.....]
print(callable(lambda x,y:x+y)) # True
print((lambda x,y:x+y)(1,2)) # 3

class MyClass(object):
    pass

if __name__ == '__main__':
    a = MyClass()
    print(a()) # TypeError: 'MyClass' object is not callable

一、__init__() 和 __new__()

__init__():创建对象、然后分配内存

__new__():初始化对象(并没有创建对象)

运行顺序是:先执行new(创建对象),再执行init(初始化)

new中:继承父类,MyClass类创建对象instance并返回,返回的对象会传给init中的self,执行初始化。

class MyClass(object):
    def __init__(self):
        print("init is running...")

    # new会先创建对象、然后分配内存
    def __new__(cls, *args, **kwargs):
        pass
        print("new is running...")
        instance = super().__new__(cls) # 创建对象(对象是由类创建的,所以是cls
        return instance

if __name__ == '__main__':
    a = MyClass()
    print(type(a))

"""
new is running...
init is running...
<class '__main__.MyClass'>
"""

二、多例模式

创建多少个对象,就分配多少个内存;每个对象独享一份内存

class MyClass(object):
    pass

if __name__ == '__main__':
    a = MyClass()
    b = MyClass()
    print(id(a))   
    print(id(b))   

三、单例模式

不管创建多少个对象,永远用同一个对象,对象只创建一次。

省内存,提高性能

1.使用__new__实现单例模式

不管创建多少对象,最终都是同一个对象,只分配一个内存地址

class MyClass(object):
    obj = None

    #如果对象已经创建 就直接把创建的对象返回
    #如果对象未创建,创建对象,并把对象返回
    def __new__(cls, *args, **kwargs):
         if cls.obj is None:
             cls.obj = super().__new__(cls)
         return cls.obj 

2. 使用装饰器实现单例模式

def singleton(cls):
    isinstance = {}

    def wrapper(*args, **kwargs):
        if not isinstance:
            isinstance[cls] = cls(*args, **kwargs)
        return isinstance[cls]

    return wrapper

@singleton
class MyClass(object):
    pass

if __name__ == '__main__':
    a = MyClass()
    b = MyClass()
    print(id(a))
    print(id(b))

3.使用import实现单例模式

deno_2.py

class MyClass(object):
    pass

myclass = MyClass()
from demo_2 import myclass
print(id(myclass)) # 2785165023752

from demo_2 import myclass
print(id(myclass)) # 2785165023752

不管import几次,只会在第一次分配内存

注意:第一次导入模块时,python解释器会创建pyc文件;以后再导入时,不会执行导入代码而是直接使用pyc文件

4.用指定的类方法实现单例模式

class MyClass(object):
    __instance  = None

    def __init__(self, *args, **kwargs):
        pass

    @classmethod
    def singleton(cls ,*args, **kwargs):
        if not cls.__instance:
            cls.__instance = cls(*args, **kwargs)
        return cls.__instance

if __name__ == '__main__':
    a = MyClass.singleton()
    b = MyClass.singleton()
    c = MyClass()
    d = MyClass()
    print(id(a))   # 2514584144968
    print(id(b))   # 2514584144968
    print(id(c))   # 2514584145032
    print(id(d))   # 2514584145096

扩展:python对象创建的内存什么时候释放?

python的垃圾回收机制(如上面的类创建的对象放在一个main()函数中,调用main函数并执行完毕后,函数内部的对象会全部销毁)

# 实现单例 与 非单例共存
class MyClass(object):
    __instance  = None

    def __init__(self, *args, **kwargs):
        pass

    @classmethod
    def singleton(cls ,*args, **kwargs):
        if not cls.__instance:
            cls.__instance = cls(*args, **kwargs)
        return cls.__instance

def main():
    a = MyClass.singleton()
    b = MyClass.singleton()
    c = MyClass()
    d = MyClass()
    print(id(a))  # 1577432513672
    print(id(b))  # 1577432513672
    print(id(c))  # 1577432513736
    print(id(d))  # 1577432513800

if __name__ == '__main__':    
    main()

要尽可能少的定义全局变量,如果不写del 变局变量,全局变量是不会被销毁的,除非程序结束。

四、创建线程安全的单例模式

线程不安全:虽然使用了单例模式,但是在多线程的情况下,单例模式“失效”了

# 线程不安全
# 多并发时,多线程造成的非单例
import threading
import time

class MyClass(object):
    __instance  = None

    def __init__(self, *args, **kwargs):
        pass

    @classmethod
    def singleton(cls ,*args, **kwargs):
        if not cls.__instance:
            cls.__instance = cls(*args, **kwargs)
        return cls.__instance

def my_obj():
    # 打印 查看创建内存
    print(MyClass.singleton())
    return MyClass.singleton()

if __name__ == '__main__':
    # 创建10个线程
    tasks = [threading.Thread(target=my_obj) for i in range(10)]
    # 同时启动10个线程
    for task in tasks:
        task.start()

"""
<__main__.MyClass object at 0x000002991B431608>
<__main__.MyClass object at 0x000002991B431708>
<__main__.MyClass object at 0x000002991B431588>
<__main__.MyClass object at 0x000002991B431508>
<__main__.MyClass object at 0x000002991B4316C8>
<__main__.MyClass object at 0x000002991B431748>
<__main__.MyClass object at 0x000002991B431688>
<__main__.MyClass object at 0x000002991B4315C8>
<__main__.MyClass object at 0x000002991B431548>
"""

如何创建线程安全的单例模式呢?-----创建锁,加锁

原理:将创建对象条件的代码段加锁,锁住后,同时只能有一个线程在创建对象,创建对象结束后,会自动释放锁。第二次再创建的时候,instance非none,就实现了单例模式了

import threading
import time

class MyClass(object):
    __instance  = None

    # 创建锁
    __lock = threading.Lock()

    def __init__(self, *args, **kwargs):
        pass

    @classmethod
    def singleton(cls ,*args, **kwargs):
        with cls.__lock:  # with 语句段 结束后会自动释放锁(unlock)
            if not cls.__instance:
                cls.__instance = cls(*args, **kwargs)
            return cls.__instance

def my_obj():
    # 打印 查看创建内存
    print(MyClass.singleton())
    return MyClass.singleton()

if __name__ == '__main__':
    # 创建10个线程
    tasks = [threading.Thread(target=my_obj) for i in range(10)]
    # 同时启动10个线程
    for task in tasks:
        task.start()
        
"""
<__main__.MyClass object at 0x000001F931AC1448>
<__main__.MyClass object at 0x000001F931AC1448>
<__main__.MyClass object at 0x000001F931AC1448>
<__main__.MyClass object at 0x000001F931AC1448>
<__main__.MyClass object at 0x000001F931AC1448>
<__main__.MyClass object at 0x000001F931AC1448>
<__main__.MyClass object at 0x000001F931AC1448>
<__main__.MyClass object at 0x000001F931AC1448>
<__main__.MyClass object at 0x000001F931AC1448>
<__main__.MyClass object at 0x000001F931AC1448>
"""
原文地址:https://www.cnblogs.com/zhangjx2457/p/14070693.html