1. 程式人生 > >Python中可變物件和不可變物件

Python中可變物件和不可變物件

之前寫了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也更改了。這是因為我們的複製是淺複製,lll指向同一個物件。

第二個例子是通過便遍歷來賦值,則變為深複製。

這和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)