一、基本概念
变量:用来标识(identify)一块内存区域。为了方便表示内存,我们操作变量实质上是在操作变量指向的那块内存单元。编译器负责分配。我们可以使用Python内建函数id()来获取变量的地址!
变量名:是一个标识符(dientify),用来代之一块内存空间,使用这个变量名,我们可以很方便的操作这块内存区域。
内存:内存是我们电脑硬件,用来存放数据,形象的理解就是内存有一个一个的小格子组成,每个格子的大小是一个字节,每个格子可以存放一个字节大小的数据。我们如何才能知道,数据存放在哪些格子中,那就得靠地址,地址类似于楼房的门牌号,是内存的标识符!
二、is和==的区别
在 Python 中一切都是对象,毫无例外整数也是对象,对象之间比较是否相等可以用==,也可以用is。
id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象。
==和is操作的区别是
"""
is
(1)比较的是两个对象的id值是否相等,也就是比较俩对象是否为同一个实例对象,是否指向同一个内存地址。
==
(2)比较的是两个对象的内容是否相等,默认会调用对象的__eq__()方法。
"""
(1)不可变类型
####(1)数字####
a = 1
b = 1
print(a == b)
print(a is b)
####(2)字符串###
str1 = 'hello&jk0'
str2 = 'hello&jk0'
print(str1 == str2) # True
print(str1 is str2) # True
"""
小结:只有数值型和字符串型的情况下,a is b才为True
"""
t1 = (1, 2, 3)
t2 = (1, 2, 3)
print(t1 == t2) # True
print(t1 is t2) # True
#注意:3.6版本的是False,3.7版本的是True(优化)
# 分析:元组中的都是不可变元素,所以二者会相等!
# 对比实验-->元组的元素是可变类型的情况下
t1 = ([1], 2, 3)
t2 = ([1], 2, 3)
print(t1 == t2) # True
print(t1 is t2) # False
(2)可变类型
列表、字典、set等
特点:==比较的是值,is比较的是不是同一个对象(深层次)!
(3)函数的说明
##细细体会元组##
##int和字符串是会先从地址池中找,找到了就把变量的引用"=",否则就开辟新的空间!
def fun(a):
b =(1,2,3) #函数是独立的一个内存空间,又开辟了一个内存空间b!
print(a==b) #True
print(a is b) #False
a=(1,2,3)
fun(a)
#同理-->列表和字典、set等一样!
三、深拷贝和浅拷贝
已知:= 赋值是多个变量资源共享(都指向同一块内存空间);带来的结果-->任意一个改变,即是对原内容的操作!
需求引入:我们偏偏需要将一份数据的原始内容保留一份,再去处理数据,这个时候就不能使用赋值了!
python为这种需求提供了copy模块,提供了两种主要的copy方法,一种是普通的copy(浅拷贝),另一种是deepcopy(深拷贝)!
(1)浅拷贝
特点:不管多么复杂的数据结构,浅拷贝都只会copy一层!
默认浅拷贝"传递对象的引用"而已,只有在复杂的数据类型中才能体现出来!
copy能不能完成浅拷贝的动作,需要看操作的数据类型是可变的还是不可变的!
不可变:相当于=
可变:相当于分身,虽然穿的衣服不一样,但是一荣俱荣,一损俱损(子对象指向相同)
#####(1)元组######
import copy
a = (1, 2, 3)
b = copy.copy(a)
print(a is b) # True -->元组是不可变数据类型-->它不会进行浅拷贝,仅仅是指向!
#####(2)列表######
c = [1, 2, 3]
d = copy.copy(c)
print(c is d) # False-->可变类型-->所以会新建!
d.pop()
print(c) # [1, 2, 3]
print(d) # [1, 2]
######(3)复杂#####
e = ([1, 2, 3], 5, 6)
f = copy.copy(e)
print(id(e[0]) == id(f[0]))
print(e is f) # True-->不可变的类型,所以不会进行浅拷贝,仅仅是指向!
e[0].append(4)
print(e) # ([1, 2, 3, 4], 5, 6)
print(f) # ([1, 2, 3, 4], 5, 6)
# g = [[1, 2], 5, 6]
g=[(1,2),5,6]
h = copy.copy(g)
print(g is h) # False -->对于可变类型,会进行浅拷贝,但它们的子对象还是指向"统一对象"!
print(id(g[0]) == id(h[0])) # True -->
# 注意:复杂的数据结构-->可变数据类型和不可变数据类型是相对于包衣(最外层而言的)
浅拷贝和深拷贝的关系和区别
a = [1, 2, (3, 4), [5, 6]]
import copy
b = copy.copy(a)
print(a is b)
a[3].append(7)
print(a)
print(b) #说明:一致!
print('----------------------')
a.append(8)
print(a)
print(b) #说明:不一致!
小结:拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。也就是把对象复制一遍,但是该对象中引用的其他对象我不复制,也就是只拷贝第一层地址!
浅拷贝:看最外层的数据类型
(2)深拷贝
特点:完全拷贝了父对象及其子对象(递归),两者是完全独立的!
说明:能不能完成完成深拷贝的动作,看是否存在可变类型的元素或者最外层是不是可变类型!
a=([1,2,3],4,(5,6,7)) False False True
a=[[1,2,3],4,(5,6,7)] False False True
#a=[[1,2,3],4,(5,[6],7)] False False False
import copy
b=copy.deepcopy(a)
print(a is b) #False -->深拷贝!
print(a[0] is b[0]) #False
print(a[2] is b[2]) #True-->此元素是不可变的数据类型