目录
- 潜复制&深复制
- 值传递&引用传递
- 可变对象&不可变对象
赋值
对象的赋值实际上是对象的引用。
当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用。
- 直接赋值
默认浅拷贝传递对象的引用而已,原始列表改变,被赋值的b也会做相同的改变
alist = [1,2,3,['a','b']]
blist = alist
- 浅拷贝
没有拷贝子对象,所以原始数据改变,子对象会改变
def add_data():
alist = [1, 2, 3, ['a', 'b']]
import copy
clist = copy.copy(alist) --没有拷贝子对象,公用一个可变list对象
print(alist, clist)
clist.append(5) --非可变子对象,不改变clist
print(alist, clist)
print(alist[3]) -- 可变改变clist
alist[3].append('qqq')
print(alist, clist)
if __name__ == '__main__':
add_data()
--输出结果
[1, 2, 3, ['a', 'b']] [1, 2, 3, ['a', 'b']]
[1, 2, 3, ['a', 'b']] [1, 2, 3, ['a', 'b'], 5]
['a', 'b']
[1, 2, 3, ['a', 'b', 'qqq']] [1, 2, 3, ['a', 'b', 'qqq'], 5]
- 深拷贝
包含对象里面的自对象的拷贝,所以原始对象的改变不会造成深拷贝里任何子元素的改变
def add_data():
alist = [1, 2, 3, ['a', 'b']]
import copy
clist = copy.deepcopy(alist)
print(alist, clist)
alist.append(5)
print(alist, clist)
print(alist[3])
alist[3].append('qqq')
print(alist, clist)
--alist始终没有改变
if __name__ == '__main__':
add_data()
--输出结果
[1, 2, 3, ['a', 'b']] [1, 2, 3, ['a', 'b']]
[1, 2, 3, ['a', 'b'], 5] [1, 2, 3, ['a', 'b']]
['a', 'b']
[1, 2, 3, ['a', 'b', 'qqq'], 5] [1, 2, 3, ['a', 'b']]
可变对象
该对象所指向的内存中的值不能被改变。
当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。
不可变对象
该对象所指向的内存中的值可以被改变。
变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的出地址,通俗点说就是原地改变。
- 数字
def add_data():
a = 2
b = 2
c = a + 0
# c += 0
print(id(a), id(b), id(2))
print(c is b)
print(a is b)
print(a == b)
if __name__ == '__main__':
add_data()
--输出结果
140721525199712 140721525199712 140721525199712
True
True
True
- 字符串
def add_data():
a = 'qly'
b = 'qly'
c = a + ''
# c += 0
print(id(a), id(b), id(2))
print(c is b)
print(a == b)
if __name__ == '__main__':
add_data()
--输出结果
2038701311344 2038701311344 140721525199712
True
True
def add_data():
a = 'qly'
print(id(a))
a += 'qq'
print(id(a))
if __name__ == '__main__':
add_data()
--输出结果
2711470425456
2711483786944
解释
不可变对象,变量对应内存的值不允许被改变。
当变量要改变时,实际上是把原来的值复制一份,开辟一个新的内存地址,a再指向这个新的地址,那么此时 id() 输出的值不一样了。
而原来a对应的值 因为不再有对象指向它,被垃圾回收了。
int 和 float 同理。元组
def add_data():
aac = (1, 2, 3)
aab = (1, 2, 3)
print(id((1, 2, 3)))
print(id(aac))
print(id(aab))
aad = (1, 2, 3)
aad += ()
print(aad)
print(id(aad))
if __name__ == '__main__':
add_data()
--输出结果
2461327044256
2461327044256
2461327044256
(1, 2, 3)
2461327044256
def add_data():
aab = (1, 2, 3)
print(id(aab))
aad = aab
aad += (4, 5, 6)
print(aad)
print(id(aad))
if __name__ == '__main__':
add_data()
--输出结果
2100321332896
(1, 2, 3, 4, 5, 6)
2100334933480
可变对象-list
def add_data():
aab = [1, 2, 3]
print(id(aab))
aac = [1, 2, 3]
print(id(aac)) --内容一样,但指向不同的内存地址
if __name__ == '__main__':
add_data()
--输出结果
2073896330632
2073896281096
--赋值
def add_data():
aab = [1, 2, 3]
print(id(aab)) -- aac 实际上是对 对象的引用,
aac = aab --值传递,两个引用指向同一个对象
print(id(aac))
# 所以其中一个变化,会影响到另外一个
aac.append(5)
print(aab)
print(id(aab),id(aac))
if __name__ == '__main__':
add_data()
--输出结果
2498063397320
2498063397320
可变对象-set
def add_data():
aab = {1, 2, 3}
aac = aab
print(id(aab))
print(id(aac))
aac.add(5)
print(aab)
print(id(aab),id(aac))
if __name__ == '__main__':
add_data()
--输出结果
2871438648936
2871438648936
{1, 2, 3, 5}
2871438648936 2871438648936
和list同理
可变对象,直接原地改变该值,不开辟新内存,改变前后id不变
def add_data():
aab = '666'
aac = aab
print(id(aab))
print(id(aac))
aac = '999' -- aab 不随 aac 的改变而改变
print(aab, aac)
print(id(aab),id(aac))
if __name__ == '__main__':
add_data()
--输出结果
2000643574784
2000643574784
666 999
2000643574784 2000643574896
def add_data():
aalist = [1,2,3]
blist = aalist[:]
print(aalist is blist)
if __name__ == '__main__':
add_data()
--输出结果
False
函数参数--值传递&引用传递
--可变类型传递的是引用,相当于对象的值
def change(aalist):
aalist.append(7)
--不可变类型传递的是内容,相当于复制再传递
def not_change(astr):
astr.lower()
if __name__ == '__main__':
test_list = [1,2,3,4]
test_str = 'HALO'
change(test_list)
not_change(test_str)
print(test_list)
print(test_str)
--输出结果
[1, 2, 3, 4, 7]
HALO
--如果不想改变原来列表的值,参数可以传入列表的拷贝
list和+
def add_data():
aa = [1,2,3]
bb = aa
print(id(aa), id(bb)) 实际上bb已经指向新的对象,id已改变
-- aa 和 bb 不是同一个对象的引用, bb变化,aa不变
bb = bb + [4] --赋值成功,bb就指向新的对象
print(id(aa), id(bb)) --不等, bb的id变了
print(aa)
cc = aa
cc += [4] --相当于调用bb.extend([4]),原地改变并没有新的对象产生
print(id(aa), id(cc)) --相等,指向同一个对象
print(aa)
if __name__ == '__main__':
add_data()
--输出结果
1532168349128 1532168349128
1532168349128 1532168348680
[1, 2, 3]
1532168349128 1532168349128
[1, 2, 3, 4]