Python实现单例模式

Python实现单例模式

 

单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
介绍
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的。
应用实例:
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))
复制代码
1
2
3
运行结果:<br>True
41816192
41816192

  

代码分析

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

 

 

补充classmethod

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

 

这里name是否相同?

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

 

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

1
2
# 第一种: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))
代码
复制代码
1
2
3
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))
复制代码
1
2
3
运行结果:<br>True
42106384
42106384

  

代码分析

1
2
3
4
5
6
#当代码执行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了。<br>#所以这里每次实例化一次对象,虽然对象还是那个对象,但是name会不一样。

  

 

posted @   -零  阅读(676)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示