作者:taowen
python中的name binding是非常好玩的,有意思。
大家還不知道什么叫name binding吧,就是假如你叫 “超人”, 然后超人就綁定到了你這個對象上,這個就是name binding了。
比如
這個的意思就是把a 綁定到了對象 1 上面。而a的類型就是number了。
再看一個例子
a也綁定到了對象[1,2,3]上面。可以這么理解[1,2,3]是一個對象存在于內存之中,而a也是一個對象,不過它是一個對象標簽一樣的對象,任務就是用來引用[1,2,3]。你能夠產生[1,2,3]這個對象,用[1,2,3]本身,或者list([1,2,3]),但是對象是一瞬即逝的。其實是一旦過去了你就沒有憑據在茫茫內存之中找到[1,2,3]這個對象了。所以要用對象,你就要有一個名字,否則只能一次性使用了,也就是臨時對象了。
比如就是這樣:
你執行完了len之后,得到3,但是之后再也沒法找到那個[1,2,3]了,那個用于len([1,2,3])的[1,2,3]了。你可能還可以用[1,2,3]產生新的對象在內存中,他們畢竟只是一樣而不是同一個。
但是你用name來綁定對象就可以做到長期使用了
這里我們又可以看到mylist+[4]其實是另外一個臨時對象了,其值應該是[1,2,3,4]。但是由于我們沒有用某個名字綁定到mylist+[4]這個臨時對象上,你將沒法在使用一次之后再次使用。
嘗試這樣一個觀點,name是一個對象,name綁定到的對象也是一個對象。
然后我們來看對于name的操作,對于name的引用大部分是作用到了name綁定的對象身上了:
可以考慮,如果name是一個對象,其本身只是用來指向一個對象。那么其屬性應該沒有len可言,當然len這個函數操作的其實是mylist指向或者說是綁定到的對象。那么
其實是len直接操作了列表[1,2,3],接收的參數是一個list,而不是一個綁定到了一個list的name。這種對于不同類型的參數表現的其實是不同的行為,一個是取出了綁定的對象求其長度,一個是直接求長度。應該看作函數的多態行為。類似的,對于操作符也有這樣的行為:
這里+號對于左右兩邊都是name,以及一邊是真實的list的兩種不同情況表現的其實是不同的行為。不用多解釋了吧,無非就是取出name綁定的對象,一個是直接操作list而已。那么再來看=號吧。
這下你明白了我的意圖嗎?打印出來的值是一樣的,但是行為是不同的。對于第一個程序。anotherlist 和mylist都是name,而不是真實的list對象。所以對于兩個name的賦值行為,其實是把左邊的name綁定到右邊那么name綁定到的對象上。這樣兩個name就綁定到了同一個對象上。而加入左邊曾經有一個綁定著的對象,那么那個對象如果沒有其他name來綁定就無法找到了。
而對于第二個程序,anotherlist被賦給的是一個真實的list,是一個用list構造函數構造出來的臨時對象(如果沒有被綁定就是臨時的了),只不過list構造函數被傳入了一個參數,一個綁定了對象的name。這樣其實anotherlist和mylist是綁定到了兩個不同的對象,但是兩個對象有相同的值。
檢驗的辦法是
分別打印的是
[4, 2, 3] [4, 2, 3]
[4, 2, 3] [1, 2, 3]
結果說明了一切。
最后提一點有關于對象回收的問題
前面多次說到了一個對象無法別找到,無法被索引到。其實當一個對象沒有name綁定到它的時候,它內部有一個引用計數,這個時候應該是為零了。這個時候將被python的運行環境給回收。因為你找不到它,也就沒法用它了,當然就可以安全的被銷毀了。而加入是這樣
由于一開始的時候是mylist和anotherlist兩個都綁定到了[1,2,3]身上,所以mylist的刪除(其實是解除綁定,當一個name沒有綁定到對象的時候就成為undefined的狀態了)并不會導致[1,2,3]這個對象的實際銷毀。
希望能夠說明一些關于名稱綁定上的問題。其實非常簡單。
python中的name binding是非常好玩的,有意思。
大家還不知道什么叫name binding吧,就是假如你叫 “超人”, 然后超人就綁定到了你這個對象上,這個就是name binding了。
比如
| 代碼: | [復制到剪貼板] | |
| ||
這個的意思就是把a 綁定到了對象 1 上面。而a的類型就是number了。
再看一個例子
| 代碼: | [復制到剪貼板] | |
| ||
a也綁定到了對象[1,2,3]上面。可以這么理解[1,2,3]是一個對象存在于內存之中,而a也是一個對象,不過它是一個對象標簽一樣的對象,任務就是用來引用[1,2,3]。你能夠產生[1,2,3]這個對象,用[1,2,3]本身,或者list([1,2,3]),但是對象是一瞬即逝的。其實是一旦過去了你就沒有憑據在茫茫內存之中找到[1,2,3]這個對象了。所以要用對象,你就要有一個名字,否則只能一次性使用了,也就是臨時對象了。
比如就是這樣:
| 代碼: | [復制到剪貼板] | |
| ||
你執行完了len之后,得到3,但是之后再也沒法找到那個[1,2,3]了,那個用于len([1,2,3])的[1,2,3]了。你可能還可以用[1,2,3]產生新的對象在內存中,他們畢竟只是一樣而不是同一個。
但是你用name來綁定對象就可以做到長期使用了
| 代碼: | [復制到剪貼板] | |
| ||
這里我們又可以看到mylist+[4]其實是另外一個臨時對象了,其值應該是[1,2,3,4]。但是由于我們沒有用某個名字綁定到mylist+[4]這個臨時對象上,你將沒法在使用一次之后再次使用。
嘗試這樣一個觀點,name是一個對象,name綁定到的對象也是一個對象。
然后我們來看對于name的操作,對于name的引用大部分是作用到了name綁定的對象身上了:
| 代碼: | [復制到剪貼板] | |
| ||
可以考慮,如果name是一個對象,其本身只是用來指向一個對象。那么其屬性應該沒有len可言,當然len這個函數操作的其實是mylist指向或者說是綁定到的對象。那么
| 代碼: | [復制到剪貼板] | |
| ||
其實是len直接操作了列表[1,2,3],接收的參數是一個list,而不是一個綁定到了一個list的name。這種對于不同類型的參數表現的其實是不同的行為,一個是取出了綁定的對象求其長度,一個是直接求長度。應該看作函數的多態行為。類似的,對于操作符也有這樣的行為:
| 代碼: | [復制到剪貼板] | |
| ||
這里+號對于左右兩邊都是name,以及一邊是真實的list的兩種不同情況表現的其實是不同的行為。不用多解釋了吧,無非就是取出name綁定的對象,一個是直接操作list而已。那么再來看=號吧。
| 代碼: | [復制到剪貼板] | |
| ||
| 代碼: | [復制到剪貼板] | |
| ||
這下你明白了我的意圖嗎?打印出來的值是一樣的,但是行為是不同的。對于第一個程序。anotherlist 和mylist都是name,而不是真實的list對象。所以對于兩個name的賦值行為,其實是把左邊的name綁定到右邊那么name綁定到的對象上。這樣兩個name就綁定到了同一個對象上。而加入左邊曾經有一個綁定著的對象,那么那個對象如果沒有其他name來綁定就無法找到了。
而對于第二個程序,anotherlist被賦給的是一個真實的list,是一個用list構造函數構造出來的臨時對象(如果沒有被綁定就是臨時的了),只不過list構造函數被傳入了一個參數,一個綁定了對象的name。這樣其實anotherlist和mylist是綁定到了兩個不同的對象,但是兩個對象有相同的值。
檢驗的辦法是
| 代碼: | [復制到剪貼板] | |
| ||
分別打印的是
[4, 2, 3] [4, 2, 3]
[4, 2, 3] [1, 2, 3]
結果說明了一切。
最后提一點有關于對象回收的問題
前面多次說到了一個對象無法別找到,無法被索引到。其實當一個對象沒有name綁定到它的時候,它內部有一個引用計數,這個時候應該是為零了。這個時候將被python的運行環境給回收。因為你找不到它,也就沒法用它了,當然就可以安全的被銷毀了。而加入是這樣
| 代碼: | [復制到剪貼板] | |
| ||
由于一開始的時候是mylist和anotherlist兩個都綁定到了[1,2,3]身上,所以mylist的刪除(其實是解除綁定,當一個name沒有綁定到對象的時候就成為undefined的狀態了)并不會導致[1,2,3]這個對象的實際銷毀。
希望能夠說明一些關于名稱綁定上的問題。其實非常簡單。
浙公網安備 33010602011771號