Python學習之共享引用
Python 學習之共享引用
什麼是共享引用
假設我們在Python互動模式下輸入以下語句:
>>> a = 3
>>> b = a
實際的效果就是變數a和b都引用了相同的物件(指向了相同的記憶體空間)。這在Python中叫做共享引用——多個變數名引用了同一個物件。
如果再來一條語句
>>> a = 'spam'
會怎麼樣?
變數a引用了由常量表示式‘spam’所建立的新物件,但是變數b仍然引用原始的物件3,因為這個賦值運算改變的不是物件3,它僅僅改變了變數a的指向,變數b並沒有發生改變。
在Python中,變數總是一個指向物件的指標,而不是可改變的記憶體區域的標籤(比如C語言中的變數)。給一個變數賦一個新值,並不是修改了原始的物件,而是讓這個變數去引用完全不同的一個物件。
注意:當可變的物件以及原處的改變進入這個場景,上述情形會有某種改變。
共享引用和在原處修改(Shared References and In-Place Changes)
有一些物件和操作確實會在原處改變物件。例如,在一個列表中通過偏移進行賦值,這確實會改變這個列表物件,而不是生成一個新的列表物件。對於支援這種在原處修改的物件,共享引用的時候一定要小心,因為對一個變數的修改會影響其他變數。
請看下面的語句:
>>> L1 = [2, 3, 4]
>>> L2 = L1
L1 是一個包含了物件2、3、4的列表。列表中的元素是通過他們的位置進行讀取的,所以L1[0]
引用物件2. 當然,列表自身也是物件,就像整數和字串一樣。在執行了上面兩行語句後,L1和L2引用了相同的物件。
現在加上第3行:
>>> L1 = [2, 3, 4]
>>> L2 = L1
>>> L1[0] = 24
我們看一下L1和L2的值:
>>> L1
[24, 3 ,4]
>>> L2
[24, 3 ,4]
在這裡,沒有改變L1,改變了L1所引用的物件的一個元素,這類修改會覆蓋列表物件中的某部分。因為這個列表物件同時被L1和L2引用,所以在原處修改不僅僅會影響L1,也會影響L2。雖然我們沒有改變L2,但是它的值將發生變化。
如果你不想要這樣的結果,那麼需要拷貝物件,而不是建立引用。有很多拷貝列表的辦法,最簡單的辦法是從頭到尾的切片。
>>> L1 = [2, 3, 4]
>>> L2 = L1[:]
>>> L1[0] = 24
>>> L1
[24, 3, 4]
>>> L2
[2, 3, 4]
這裡,對L1的修改不會影響L2,因為L2引用的是L1所引用物件的一個拷貝。也就是說,L1和L2指向了不同的記憶體區域。
共享引用和相等
>>> x = 42
>>> x = 'shrubbery'
因為Python快取並複用了小的整數和小的字串,執行完這兩行程式碼後,物件42也許不會被回收;相反地,它可能仍被儲存在一個系統表中,等待下一次你的程式碼生成另一個42來重複利用。儘管這樣,大多數種類的物件都會在不被引用的時候馬上回收。
在Python中有2種不同的方法去檢查兩個變數是否相等。
>>> L = [1, 2, 3]
>>> M = L # M and L reference the same object
>>> L == M # Same values
True
>>> L is M # Same objects
True
==
操作符測試兩個被引用的物件是否有相同的值,這種方法往往在Python中用作相等的檢查。
is
操作符用來檢查物件的同一性。如果兩個變數名都指向同一個物件,則會返回 True,所以這是一種更嚴格的相等測試。
實際上,is
只是比較實現引用的指標,所以這是一種檢測共享引用的方法。如果變數名指向不同的物件,就算這兩個物件的值相等,也會返回 False.
例如:
>>> L = [1, 2, 3]
>>> M = [1, 2, 3] # M and L reference different objects
>>> L == M # Same values
True
>>> L is M # Different objects
False
如果對小的數字進行類似測試:
>>> X = 42
>>> Y = 42 # Should be two different objects
>>> X == Y
True
>>> X is Y # Same object anyhow: caching at work!
True
按理來說,第3~4行是可以理解的,因為兩個物件的值一樣;但是第5~6行就讓人匪夷所思了,X引用的42和Y引用的42本來是2個物件,應該輸出False才對,不過,因為小的整數和字串被快取並複用了,所以is
告訴我們X和Y引用了同一個物件。
實際上,你可以用sys
模組中的getrefcount
函式查詢物件的被引用次數。例如,我們查一下整數1被引用的次數:
>>> import sys
>>> sys.getrefcount(1)
812
這種物件快取和複用的機制與程式碼是沒有關係的。Python這樣做是為了提高執行速度。
【End】
參考資料
《Python學習手冊(第4版)》,機械工業出版社
相關文章
- Python學習之變數、物件和引用Python變數物件
- Python學習之如何引用Python自定義模組?Python
- python3學習筆記之 強引用和弱引用Python筆記
- Python 弱引用 學習Python
- python開發學習之如何更好的引用Python模組?Python
- C++ 學習筆記之 引用C++筆記
- Python學習之模組Python
- Python之numpy學習Python
- python之pandas學習Python
- Python之Series 學習Python
- MongoDB學習筆記之索引用法和效率分析MongoDB筆記索引
- java基礎學習之五:引用資料型別Java資料型別
- 【python】python 模組學習之--FabricPython
- 【python】python 模組學習之--pexpectPython
- Python 學習之元組Python
- Python學習之set集合Python
- python學習之運算子Python
- python學習之數字Python
- Python學習之函式Python函式
- Python學習之常用模組Python
- Python學習之正則Python
- python學習之argparse模組Python
- Python學習筆記|Python之程式Python筆記
- C#學習筆記之值型別與引用型別C#筆記型別
- python學習之訊號量Python
- Python學習之 datetime模組Python
- Python學習之引數(一)Python
- Python學習之zip函式Python函式
- Python學習之模組與包Python
- Python 學習之元組列表Python
- pandas學習之Python基礎Python
- python庫學習之Requests(二)Python
- Python學習筆記之序列Python筆記
- Python學習之路27-物件引用、可變性和垃圾回收Python物件
- Python學習筆記|Python之yield理解Python筆記
- Python學習筆記|Python之索引迭代Python筆記索引
- Python學習筆記|Python之特殊方法Python筆記
- Python學習系列之學Python需要什麼軟體?Python