单例模式与原型模式
浏览 1513
课文
单例模式(Singleton Pattern)
单例模式非常容易理解:当你希望程序在运行时某个类有且仅有一个实例时,就可以使用单例模式。
python 的单例模式也很容易实现:
class Singleton:
# __new__()方法是类的构造函数,先于__init_()_方法执行
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'): # 用hasattr()方法判断这个类是否已有实例
cls._instance = super().__new__(cls)
return cls._instance
一个简单的单例模式类就构造好了,如何判断它是否只有一个实例呢?我们知道,每实例化一次类,都会在内存空间中开辟新的储存空间用于存放这个实例,那么只需要多次实例化这个类,判断是否相等就知道了:
s1 = Singleton()
s2 = Singleton()
s3 = Singleton()
print(s1 == s2 == s3)
输出:
True
说明这个类在运行过程中只有一个实例。
原型模式(Prototype Pattern)
如果你拥有一个类的实例化对象,且希望获得若干个它的复制品,那么该如何实现呢?
python 里面提供了一个叫做copy
的模块,其中两个方法copy
和deepcopy
可以返回对象的浅拷贝和深拷贝,下面是示例代码:
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()
输出:
<__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
则会进行深拷贝。我们修改一下上面的代码:
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()
输出:
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 等)储存在栈里,使用赋值操作符
=
时会重新复制一份:
a = 1
b = a # 这里相当于b = 1
a = 2
print(b)
输出:
1
- 而引用数据类型(list,dict 等)则会指向内存地址,改变它内部的数据并不会改变它的内存指向:
a = [1]
b = a # 这里相当于将数组的内存地址同时赋值给了a和b
a[0] = 2 # 改变数组内部元素不会影响其内存地址
print(b)
输出:
[2]
从以上例子可以看出,deepcopy
方法更接近于生活中我们所理解的「复制」概念。那为什么还要copy
方法呢?实际上,进行深拷贝时会占用较多性能,而简单的业务场景进行深拷贝会显得有些多余,于是采取了浅拷贝方式去节约性能。
评论
暂无评论