1. 程式人生 > >python 深入變數和引用物件

python 深入變數和引用物件

變數和物件

在《learning python》中的一個觀點:變數無型別,物件有型別

在python中,如果要使用一個變數,不需要提前宣告,只需要在用的時候,給這個變數賦值即可。這裡特別強調,只要用一個變數,就要給這個變數賦值。

所以,像這樣是不行的。

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

反覆提醒:一定要注意看報錯資訊。如果光光地寫一個變數,而沒有賦值,那麼python認為這個變數沒有定義。賦值,不僅僅是給一個非空的值,也可以給一個空值,如下,都是允許的

>>> x = 3
>>> lst = []
>>> word = ""
>>> my_dict = {}

image.png

看到上面的圖了吧,從圖中就比較鮮明的表示了變數和物件的關係。所以,嚴格地將,只有放在記憶體空間中的物件(也就是資料)才有型別,而變數是沒有型別的。

同一個變數可以同時指向兩個物件嗎?

>>> x = 4
>>> x = 5
>>> x
5

變數x先指向了物件4,然後指向物件5,自動跟第一個物件4解除關係。再看x,引用的物件就是5了。那麼4呢?一旦沒有變數引用它了,便成了垃圾,python有一個自動的收回機制。
例如:

>>> a = 100         #完成了變數a對記憶體空間中的物件100的引用

image.png

然後,又操作了:

>>> a = "hello"

如下圖所示:

image.png

原來記憶體中的那個100就做為垃圾被收集了。而且,這個收集過程是python自動完成的,不用我們操心。

那麼,python是怎麼進行垃圾收集的呢?在Quora上也有人問這個問題,我看那個回答很精彩,做個連結:Python (programming language): How does garbage collection in Python work?

is和==的效果

以上過程的原理搞清楚了,下面就可以深入一步了。

>>> l1 = [1,2,3]
>>> l2 = l1

這個操作中,l1和l2兩個變數,引用的是一個物件,都是[1,2,3]。何以見得?如果通過l1來修改[1,2,3],l2引用物件也修改了,那麼就證實這個觀點了。

>>> l1[0] = 99      #把物件變為[99,2,3]
>>> l1              #變了
[99, 2, 3]
>>> l2             #真的變了吔
[99, 2, 3]

再換一個方式:

>>> l1 = [1,2,3]
>>> l2 = [1,2,3]
>>> l1[0] = 99
>>> l1
[99, 2, 3]
>>> l2
[1, 2, 3]

l1和l2貌似指向了同樣的一個物件[1,2,3],其實,在記憶體中,這是兩塊東西,互不相關。只是在內容上一樣。所以,當通過l1修改引用物件的後,l2沒有變化。

進一步還能這麼檢驗:

>>> l1
[1, 2, 3]
>>> l2
[1, 2, 3]
>>> l1 == l2    #兩個相等,是指內容一樣
True
>>> l1 is l2    #is 是比較兩個引用物件在記憶體中的地址是不是一樣
False          #前面的檢驗已經說明,這是兩個東東

>>> l3 = l1   #順便看看如果這樣,l3和l1應用同一個物件
>>> l3
[1, 2, 3]
>>> l3 == l1
True
>>> l3 is l1    #is的結果是True
True

某些物件,有copy函式,通過這個函式得到的物件,是一個新的還是引用到同一個物件呢?
實驗:

>>> l1
[1, 2, 3]
>>> l2 = l1[:]
>>> l2
[1, 2, 3]
>>> l1[0] = 22
>>> l1
[22, 2, 3]
>>> l2
[1, 2, 3]

>>> adict = {"name":"hiekay","web":"hiekay.github.io"}
>>> bdict = adict.copy()
>>> bdict
{'web': 'hiekay.github.io', 'name': 'hiekay'}
>>> adict["email"] = "[email protected]"
>>> adict
{'web': 'hiekay.github.io', 'name': 'hiekay', 'email': '[email protected]'}
>>> bdict
{'web': 'hiekay.github.io', 'name': 'hiekay'}

不過,python不總按照前面說的方式,比如小數字的時候

>>> x = 2
>>> y = 2
>>> x is y
True
>>> x = 200000
>>> y = 200000
>>> x is y      #什麼道理呀,小數字的時候,就用快取中的.
False

>>> x = 'hello'
>>> y = 'hello'
>>> x is y
True
>>> x = "what is you name?"
>>> y = "what is you name?"
>>> x is y      #不光小的數字,短的字串也是
False

賦值是不是簡單地就是等號呢?從上面得出來,=的作用就是讓變數指標指向某個物件。