Python中有可變對象和不可變對象之分。可變對象建立後可改變但地址不會改變,即變量指向的仍是原來的變量;不可變對象建立以後便不能改變,若是改變則會指向一個新的對象。python
Python中dict、list是可變對象,str、int、tuple、float是不可變對象。緩存
本文只介紹list和str,其餘的同理。bash
來看一個字符串的例子:微信
>>> a = "hello"
>>> a[0] = 'a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
複製代碼
上面提示,字符串類型是不支持元素賦值的,也就是說字符串是不可變對象。而當咱們對字符串拼接的時候,Python會建立一個新的字符串對象:app
a = "hello"
print(id(a)) # 2240543256736
a = a + " world"
print(id(a)) # 2240542770544
複製代碼
執行a = a + " world"
時,先計算等號右邊的表達式,生成一個新的對象賦值到變量a,所以a指向的對象發生了改變,id(a)
的值也與原先不一樣。函數
再來看一個列表的例子:學習
a = [1, 2, 3]
print(id(a)) # 2240541319816
a[0] = 5
print(id(a)) # 2240541319816
a.append(6)
print(id(a)) # 2240541319816
b = a
print(id(b)) # 2240541319816
c = b[:]
print(id(c)) # 2240541319880
c[3]=0
print(a) # [5, 2, 3, 6]
print(b) # [5, 2, 3, 6]
print(c) # [5, 2, 3, 0]
複製代碼
咱們能夠看到,當更改列表元素的值、追加元素等,列表始終指向同一個對象。咱們把a賦給b之後,b也指向了同一個對象。而當把b的切片賦給c時,改變c以後,a和b未受影響,說明c指向了不一樣的對象。ui
切片操做是淺拷貝。而普通的賦值只是複製對象的索引(對象標識符、內存地址)給等號左邊的變量。spa
下面來看個有趣的例子:code
class Group(object):
def __init__(self, group_id, members=[]):
self.group_id = group_id
self.members = members
def add_member(self, member):
self.members.append(member)
group1 = Group(1)
group1.add_member('Zhang')
group1.add_member('Li')
print(id(group1)) # 139975434248880
print(group1.members) # ['Zhang', 'Li']
group2 = Group(2)
group2.add_member('Wang')
group2.add_member('Chen')
print(id(group2)) # 139975434248992
print(group2.members) # ['Zhang', 'Li', 'Wang', 'Chen']
複製代碼
咱們能夠看到,雖然group1和group2是不一樣的對象,可是group2中的members列表,group1中的members列表也變了。難道他們是同一個列表?咱們來驗證一下:
print(id(group1.members)) # 139662719359368
print(id(group2.members)) # 139662719359368
複製代碼
果真是同一個列表,緣由是__init__
函數的第二個參數是默認參數,默認參數的默認值在函數建立的時候就生成了,每次調用都是用了這個對象的緩存。
因此,group1.members
和group2.members
指向了同一個對象,對group2.members
的修改也會影響group1.members
。
那麼如何解決這個問題呢?方法很簡單,咱們將默認值設爲None便可:
class Group(object):
def __init__(self, group_id, members=None):
self.group_id = group_id
if members is None:
self.members = []
def add_member(self, member):
self.members.append(member)
group1 = Group(1)
group1.add_member('Zhang')
group1.add_member('Li')
print(id(group1)) # 139879060173432
print(group1.members) # ['Zhang', 'Li']
group2 = Group(2)
group2.add_member('Wang')
group2.add_member('Chen')
print(id(group2)) # 139879060173544
print(group2.members) # ['Wang', 'Chen']
print(id(group1.members)) # 140296455689224
print(id(group2.members)) # 140296462760328
複製代碼
這樣對於不一樣的group對象,它們的members是在函數被調用時才被建立,不一樣的group對象中的members再也不引用同一個對象,因此不會再出現更新一個group對象的members也會更新另一個group對象的members了。
Python交流學習羣:532232743
微信公衆號:小鑫的代碼平常