单例模式与原型模式

浏览 548

课文

### 单例模式(Singleton Pattern) 单例模式非常容易理解:当你希望程序在运行时某个类有且仅有一个实例时,就可以使用单例模式。 python 的单例模式也很容易实现: ```python class Singleton: # __new__()方法是类的构造函数,先于__init_()_方法执行 def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): # 用hasattr()方法判断这个类是否已有实例 cls._instance = super().__new__(cls) return cls._instance ``` 一个简单的单例模式类就构造好了,如何判断它是否只有一个实例呢?我们知道,每实例化一次类,都会在内存空间中开辟新的储存空间用于存放这个实例,那么只需要多次实例化这个类,判断是否相等就知道了: ```python s1 = Singleton() s2 = Singleton() s3 = Singleton() print(s1 == s2 == s3) ``` 输出: ```output True ``` 说明这个类在运行过程中只有一个实例。 ### 原型模式(Prototype Pattern) 如果你拥有一个类的实例化对象,且希望获得若干个它的复制品,那么该如何实现呢? python 里面提供了一个叫做`copy`的模块,其中两个方法`copy`和`deepcopy`可以返回对象的浅拷贝和深拷贝,下面是示例代码: ```python from copy import copy, deepcopy # 定义Student类,拥有一些属性和一个打印属性的方法 class Student: def __init__(self, name=None, age=None, grade=None, score=[]): self.name = name self.age = age self.grade = grade self.score = score def get_attr(self): print(self.name, self.age, self.grade, self.score) score = [100, 100, 100] # 创建一个Student类的对象t,初始化一些属性的值 t = Student('111', 7, 2, score) # 分别对t进行浅拷贝和深拷贝 t_copy = copy(t) t_deepcopy = deepcopy(t) # 打印其内存地址与值 print(t) print(t_copy) print(t_deepcopy) t.get_attr() t_copy.get_attr() t_deepcopy.get_attr() ``` 输出: ```output <__main__.Student object at 0x000002BF42B57B80> <__main__.Student object at 0x000002BF42B287C0> <__main__.Student object at 0x000002BF42B63610> 111 7 2 [100, 100, 100] 111 7 2 [100, 100, 100] 111 7 2 [100, 100, 100] ``` 这就是 python 里关于原型模式的使用方法。可以看到,三者之间的内存地址互不相同,但值是一样的,利用这两个方法我们可以快速获得一个类的多个对象。 那么`copy`和`deepcopy`有什么区别呢?实际上`copy`只会进行浅拷贝,而`deepcopy`则会进行深拷贝。我们修改一下上面的代码: ```python from copy import copy, deepcopy class Student: def __init__(self, name=None, age=None, grade=None, score=[]): self.name = name self.age = age self.grade = grade self.score = score def get_attr(self): print(self.name, self.age, self.grade, self.score) score = [100, 100, 100] t = Student('111', 7, 2, score) t_copy = copy(t) t_deepcopy = deepcopy(t) score[1] = 99 # 这里是新增一段代码修改score的值 t.get_attr() t_copy.get_attr() t_deepcopy.get_attr() ``` 输出: ```output 111 7 2 [100, 99, 100] 111 7 2 [100, 99, 100] 111 7 2 [100, 100, 100] ``` 我们会发现,`t_copy`的`score`同样被改变了,而`t_deepcopy`则没有改变。这里需要介绍一下 python 的内存机制: - 基本数据类型(str、int 等)储存在栈里,使用赋值操作符`=`时会重新复制一份: ```python a = 1 b = a # 这里相当于b = 1 a = 2 print(b) ``` 输出: ```output 1 ``` - 而引用数据类型(list,dict 等)则会指向内存地址,改变它内部的数据并不会改变它的内存指向: ```python a = [1] b = a # 这里相当于将数组的内存地址同时赋值给了a和b a[0] = 2 # 改变数组内部元素不会影响其内存地址 print(b) ``` 输出: ```output [2] ``` 从以上例子可以看出,`deepcopy`方法更接近于生活中我们所理解的「复制」概念。那为什么还要`copy`方法呢?实际上,进行深拷贝时会占用较多性能,而简单的业务场景进行深拷贝会显得有些多余,于是采取了浅拷贝方式去节约性能。

评论

登录参与讨论

暂无评论

共 0 条
  • 1
前往
  • 1