浅拷贝
- 列表的浅拷贝遵循如下规则:
- 如果元素是基本类型数据,采用值拷贝的方式,修改本体副本不受影响,反之亦然;
- 如果元素是对象类型数据,采用地址引用的方式,修改本体副本受到影响,反之亦然;
- 深拷贝则无论元素是基本类型还是对象类型,都是值拷贝方式,本体副本完全独立,修改时互不影响;
a = [1, 2, ["a", "b"]]
b = a # b=[1, 2, ["a", "b"]]
# c=[1, 2, ["a", "b"]]
# 1,2基本类型是值拷贝,["a", "b"]对象类型是地址引用
c = a.copy()
# 本体和副本中的对象类型数据具有相同的地址
print(id(a[-1]), id(c[-1]))
# 修改基本类型数据不会影响浅拷贝副本
a[0] = -1
# 修改本体的非对象类型数据,不会影响副本
a.insert(0, 3)
# 修改本体中的对象类型数据,副本受到影响,反之亦然
a[-1].append(3)
c[-1].append("4")
print(a, c) # a=[3,1, 2, ["a", "b",3,"4"]],c=[1, 2, ["a", "b",3,"4"]]
- 对象传参
- 在给函数传参时,基本数据类型和对象数据类型分别遵循如下规则:
- 基本类型的传参采用值拷贝的方式,函数内无论如何修改传入的基本类型数据,外界都不受影响;
- 对象类型的传参采用地址引用的方式,函数内对对象的修改,外界受到影响;
from MyRepr import Person
# 这里的arg是整型,person是对象类型
def func(arg=1, person=None):
# 修改基本类型数据不影响外界
arg = 456
# 函数内的对象和函数外具有相同的地址
global p
print(id(arg), id(p))
# 修改对象属性,外界受到影响
person.name = "jobs"
arg = 123
p = Person("bill", 60)
# 将基本类型arg和对象类型p一起传递给函数
# 基本类型arg是以值拷贝的形式传递的
# 对象类型p是以地址引用的方式传递的
func(arg, p)
# 基本类型数据arg没有受到函数修改的影响
# 对象类型数据p的属性被函数所修改了
print(arg, p.name)
- 总结
- 无论是浅拷贝,还是函数传参,对象类型数据的传递都是以地址引用的方式进行的;
- 此时无论修改本体还是副本中的对象,无论修改函数内还是函数外的对象,另一方都会随之一起改变;