python的单例模式和__new__方法

单例模式是一个常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。比如说:利用加标签的白名单防止跨站脚本攻击XXS创建一个XxsFile类,不同的人访问都要创建XxsFile对象的实例,这就导致系统中存在多个XxsFile的实例对象,而这样会严重浪费内存资源。事实上类似于XxsFile这样的类,我们希望在程序运行期间只存在一个实例对象,在python中,我们可以使用单例。如下列几种方法:


在Python中new方法和init方法类似,但是如果两个都存在那么new先执行

__new__(cls, *args, **kwargs)

__new__()中的需要传递一个参数cls,cls表示需要实例化的类,此参数在实例化时由Python解析器自动提供

1、类方法classmethod

# -*-coding:utf-8 -*-
class Foo(object):
    __instance = None

    @classmethod
    def instance(self):
        if self.__instance:
            return self.__instance

        else:
            obj = self()
            self.__instance = obj
            return self.__instance
obj1=Foo.instance()
obj2=Foo.instance()
print(obj1,obj2)

2、基于__new__方法实现(推荐使用、方便)

当我们实例化一个对象时,是先执行了类的__new__方法(当我们没写时,默认调用object.__new__),实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,所以我们可以基于这个,实现单例模式:

# -*-coding:utf-8 -*-
class Foo(object):
    __instance=None
    def __init__(self):
        pass
    def __new__(cls, *args, **kwargs):

        if cls.__instance:
            return cls.__instance
        else:
            obj = object.__new__(cls,*args,**kwargs)
            cls.__instance = obj
            return cls.__instance
obj1=Foo()
obj2=Foo()
print(obj1,obj2)

Python new()方法,为对象分配内存,返回对象的引用

# -*-coding:utf-8 -*-
class MusicPlayer(object):

    #为对象分配内存空间
    def __new__(cls, *args, **kwargs):

        #1、创建对象时,new方法会被自动调用
        print("创建对象,分配内存空间")

        #2、为对象分配空间
        instance = super().__new__(cls)

        #3、返回对象引用
        return instance
    #对象初始化,定义实例属性
    def __init__(self):
        print("播放器初始化")

#创建播放器对象
player = MusicPlayer()
print(player)

__new__方法:

使用MusicPlayer()创建对象时,python的解释器首先会调用__new__方法为对象分配空间,如果不分配空间那么就不会调用初始化__init____new__是一个由object基类提供的内置的静态方法,主要作用有两个:

1、在内存空间中为对象分配空间

2、返回对象的引用

Python的解释器获取得到对象的引用后,将引用作为第一个参数,传递给__init__,

1、重写__new__方法python用return super().__new__(cls),否则Python的解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法,注意:__new__是一个静态方法,在调用时需要主动传递cls参数

如果分配了内存空间,就会调用初始化__init__的结果:

# -*-coding:utf-8 -*-
class MusicPlayer(object):

    #为对象分配内存空间
    def __new__(cls, *args, **kwargs):

        #1、创建对象时,new方法会被自动调用
        print("创建对象,分配内存空间")

        #2、为对象分配空间
        instance = super().__new__(cls)

        #3、返回对象引用
        return instance
    #对象初始化,定义实例属性
    def __init__(self):
        print("播放器初始化")

#创建播放器对象
player = MusicPlayer()
print(player)

#输出:
    # 创建对象,分配内存空间
    # 播放器初始化
    # <__main__.MusicPlayer object at 0x033D09B0>

如果__new__不分配内存空间,创建对象的时候就不会去的调用__init__,结果如下:

    # -*-coding:utf-8 -*-
class MusicPlayer(object):

    #为对象分配内存空间
    def __new__(cls, *args, **kwargs):

        #1、创建对象时,new方法会被自动调用
        print("创建对象,分配内存空间")

        
    #对象初始化,定义实例属性
    def __init__(self):
        print("播放器初始化")

#创建播放器对象
player = MusicPlayer()
print(player)

#输出:
    #创建对象,分配内存空间
    #None