Python中可變物件和不可變物件
阿新 • • 發佈:2019-02-19
之前寫了FPGrowth的程式碼,寫得非常噁心,覺得和C語言、C++的工程檔案很不相同。其中就有關於傳引用、傳值的疑問。
截一段Leetcode的程式碼
這題好像是Leetcode 93附近的一道 獲得二叉樹最大深度的題目。
我使用了dfs,本來以為python是傳物件引用的,所以在dfs中更新了ans,那麼返回的ans也會改變,但是最後得到的結果保持1。
經過檢視資料我就知道這和命名域以及可變物件和不可變物件有關。
那麼我們來說一說可變物件和不可變物件。
列表
先看下面的例子:
>>> l = [1, 2, 3]
>>> ll = l
>>> ll.remove(1)
>>> l
[2, 3]
>>>
>>>a = [1]
>>>b = a
>>>b[0] = 2
>>>a
[2]
>>> l = [1, 2, 3]
>>> ll = l[:]
>>> ll.remove(1)
>>> l
[1, 2, 3]
>>>
列表是可變物件型別,因此傳遞的時候,變數名b繫結的記憶體地址與a繫結的記憶體地址是同一地址。
我們可以看到,在第一個例子中,我們更改了ll
l
也更改了。這是因為我們的複製是淺複製,ll
和l
指向同一個物件。
第二個例子是通過便遍歷來賦值,則變為深複製。
這和copy中的copy、deepcopy類似。
數值
>>> x = 1
>>> y = 1
>>> x is y
True
>>>id(x) == id(y)
False
數值為不可變型別,x與y指向的是數值為1的同一記憶體地址。
類
對於類來說也是如此:
class b:
x = []
def set(self):
self.x.append(1 )
def get(self):
return self.x
for i in range(3):
a = b()
print b.__dict__
a.set()
print a.get()
'''
{'x': [], '__module__': '__main__', 'set': <function set at 0x7f89a319bcf8>, '__doc__': None, 'get': <function get at 0x7f89a319bd70>}
[1]
{'x': [1], '__module__': '__main__', 'set': <function set at 0x7f89a319bcf8>, '__doc__': None, 'get': <function get at 0x7f89a319bd70>}
[1, 1]
{'x': [1, 1], '__module__': '__main__', 'set': <function set at 0x7f89a319bcf8>, '__doc__': None, 'get': <function get at 0x7f89a319bd70>}
[1, 1, 1]
'''
python中,萬物皆物件。python中不存在所謂的傳值呼叫,一切傳遞的都是物件的引用,也可以認為是傳址。
python中,物件分為可變(mutable)和不可變(immutable)兩種型別。
元組(tuple)、數值型(number)、字串(string)均為不可變物件,而字典型(dictionary)和列表型(list)的物件是可變物件。
>>>a = 1 #將名字a與記憶體中值為1的記憶體繫結在一起
>>>a = 2 #將名字a與記憶體中值為2的記憶體繫結在一起,而不是修改原來a繫結的記憶體中的值,這時,記憶體中值為1的記憶體地址引用計數-1,當引用計數為0時,記憶體地址被回收
>>>b = a #變數b執行與a繫結的記憶體
>>>b = 3 #建立一個記憶體值為3的記憶體地址與變數名字b進行繫結。這是a還是指向值為2的記憶體地址。
>>>a,b
>>>(2,3)