Python实现单例模式

 

单例模式

介绍
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的。
应用实例:
1、一个班级只有一个班主任。
2、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
使用场景:
1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

  

 

第一种方法

 1 class User(object):
 2     #定义类属性
 3     __instance=None
 4     #初始化方法
 5     def __init__(self,name):
 6         self.name=name
 7 
 8     @classmethod
 9     #定义类方法
10     def get_instance(cls,name):
11         #如果__instance为空,则执行
12         if not cls.__instance:
13             #实例化对象,并赋值给__instance属性
14             cls.__instance=User(name)
15         return cls.__instance
16 u1 =User.get_instance("lili")
17 u2 = User.get_instance("lisi")
18 print(u1==u2)
19 print(id(u1))
20 print(id(u2))
运行结果:
True 41816192 41816192

  

代码分析

# 要实现不管实例化多少次,拿到的都是同一个对象
# 这里我们通过调用类的静态方法来实例化类(@classmethod)
# 第一次实例化对象的时候,类属性为空,则会初始化对象,并返回对象
# 第二次时,类属性已不为空,则不会实例化对象,直接返回第一次生成的对象
关键点:通过类静态方法实例化对象
     __instance类属性的作用

 

 

补充classmethod

classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。

View Code

 

这里name是否相同?

# 我们是使用通过调用类的静态方法来实例化对象的,所以这里不会直接执行__init__方法,是在静态方法里间实例化时执行了__init__方法,并且只会执行一次。
# 这里每次实例化一次对象,拿到的对象是同一个对象,name也相同。

 

有一个问题?我们知道有两种方法初始化对象,如果我们使用User(“lili”)来实例化对象会怎样?

# 第一种:u1=User("lili")  #通过 __init__实例化对象
# 第二种:u1=get_instance("lili")  #通过类的静态方法间接实例化对象

  

class User(object):
    #定义类属性
    __instance=None
    #初始化方法
    def __init__(self,name):
        self.name=name

    @classmethod
    #定义类方法
    def get_instance(cls,name):
        #如果__instance为空,则执行
        if not cls.__instance:
            #实例化对象,并赋值给__instance属性
            cls.__instance=User(name)
        return cls.__instance
u1 =User("lili")
u2 = User("lisi")
print(u1==u2)
print(id(u1))
print(id(u2))

代码

False
36376704
36376760

  

 

第二种方法

 1 class User(object):
 2     #定义类属性
 3     __instance=None
 4     #初始化方法
 5     def __init__(self,name):
 6         self.name=name
 7     def __new__(cls,name):
 8         #保证object.__new__(cls)方法只会调用第一次
 9         if not cls.__instance:
10             #object.__new__(cls)创建对象
11             cls.__instance=object.__new__(cls)
12         return cls.__instance
13 u1 = User("lili")
14 u2 = User("lisi")
15 print(u1==u2)
16 print(id(u1))
17 print(id(u2))
运行结果:
True 42106384 42106384

  

代码分析

#当代码执行u1 = User("lili")
# 会运行到__new__方法,此时类属性__instance为空,则会创建对象,把对象赋值给__instance,并返回对象
# 现在代码还没有运行完,会继续执行__init__方法,会将"lili"赋值给name,现在name="lili"
# 执行u1 = User("lili"),类属性不为空,不会创建对象,直接返回第一次创建的对象
#此时是最重要的,def __init__(self,name)中self为第一次的对象,而传进来的name为第二次的name,就会将"lisi"赋值给name,现在name="lisi"
# 但是对象永远都是那个对象,name却不是那个name了。
#所以这里每次实例化一次对象,虽然对象还是那个对象,但是name会不一样。

  

 

版权声明:本文为-wenli原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/-wenli/p/10433503.html