來源: ApacheCN『USF MSDS501 計算數據科學中文講義』翻譯項目原文:Data Aliasingpython
譯者:飛龍git
協議:CC BY-NC-SA 4.0程序員
編程最棘手的事情之一是確切地肯定變量所指的數據。 請記住,咱們使用data
和salary
這樣的名稱來表示保存數據值的內存單元。 名稱比物理內存地址更容易記住,但咱們可能被愚弄。 例如,顯然兩個變量x
和y
均可以具備相同的整數值 7:github
x = y = 7 print(x,y) # 7 7
可是,你知道他們都指的是同一個 7 對象嗎? 換句話說,Python 中的變量始終是引用或指向數據的指針,所以變量在技術上並非持有值。 指針就像電話號碼「指向」手機,但指針自己不是手機自己。apache
咱們可使用內置的id(x)
函數來發現這個間接的祕密層次,該函數返回由x
指向的物理內存地址。 爲了證實這一點,讓咱們問一下x
和y
指向的是什麼:編程
x = y = 7 print(id(x)) print(id(y)) ''' 4468307488 4468307488 '''
哇! 他們是同樣的。 該數字表示 Python 存儲共享對象 7 的內存位置。數組
固然,做爲程序員,咱們並不認爲這些原子元素指的是同一個對象;請記住他們這樣作。 咱們更有可能將它們視爲相同數字的副本,由於lolviz
在視覺上顯示:數據結構
from lolviz import * callviz(varnames=['x','y'])
讓咱們驗證字符串是否發生了一樣的事情:svg
name = 'parrt' userid = name # userid now points at the same memory as name print(id(name)) print(id(userid)) ''' 4506178760 4506178760 '''
好的,很好,因此咱們實際上共享相同的內存地址來保存字符串'parrt'
,而且兩個變量名都指向同一個共享空間。咱們在語言實現中稱之爲別名。函數
當咱們開始更改共享數據時,事情纔會變得怪異。整數和字符串不會發生這種狀況,由於它們是不可變的(沒法更改)。讓咱們看一個列表的兩個相同副本:
you = [1,3,5] me = [1,3,5] print(id(you)) print(id(me)) callviz(varnames=['you','me']) ''' 4508962504 4508962440 '''
這些列表具備相同的值,但存在不一樣的內存地址。他們不是別名;它們不是共享的。所以,更改一個不會改變另外一個:
you = [1,3,5] me = [1,3,5] print(you, me) you[0] = 99 print(you, me) ''' [1, 3, 5] [1, 3, 5] [99, 3, 5] [1, 3, 5] '''
另外一方面,讓咱們看看若是咱們讓you
和me
共享相同的列表副本(指向相同的內存位置)會發生什麼:
you = [1,3,5] me = you print(id(you)) print(id(me)) print(you, me) callviz(varnames=['you','me']) ''' 4509139464 4509139464 [1, 3, 5] [1, 3, 5] '''
如今,更改一個彷佛改變另外一個,但實際上二者都恰好引用內存中的相同位置:
you[0] = 99 print(you, me) callviz(varnames=['you','me']) # [99, 3, 5] [99, 3, 5]
不要混淆「更改列表元素」和「更改指向列表的指針」:
you = [1,3,5] me = you callviz(varnames=['you','me'])
me = [9,7,5] # doesn't affect `you` at all print(you) print(me) callviz(varnames=['you','me']) ''' [1, 3, 5] [9, 7, 5] '''
當咱們將列表或其餘數據結構傳遞給函數時,這種數據別名大量存在。 將Quantity
列表傳遞給其參數名爲data
的函數,意味着這兩個是別名。 咱們將在使用函數組織代碼的「符號可見性」部分中,更詳細地查看這個現象。
X = [[1,2],[3,4]] Y = X.copy() # shallow copy callviz(varnames=['X','Y'])
X[0][1] = 99 callviz(varnames=['X','Y']) print(Y) # [[1, 99], [3, 4]]