作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!
謝謝TeaEra, 貓咪cat
動態類型(dynamic typing)是Python另一個重要的核心概念。我們之前說過,Python的變數(variable)不需要聲明,而在賦值時,變數可以重新賦值為任意值。這些都與動態類型的概念相關。
1. 動態類型
在我們接觸的對象中,有一類特殊的對象,是用於儲存資料的。常見的該類對象包括各種數字,字串,表,詞典。在C語言中,我們稱這樣一些資料結構為變數。而在Python中,這些是對象。
對象是儲存在記憶體中的實體。而我們的變數,實際上只是指向這一對象的參考(reference),類似於C語言的指標。
(在C語言中,變數自身就是儲存於記憶體中的實體)
變數和它所指的對象的分離,就是動態類型的核心。由於變數只類似於一個指標,所以它可以隨時指向一個新的對象,即使這個新的對象的類型發生了變化。
a = 3a = 'at'
第一個語句中,3是儲存在記憶體中的一個整數對象。通過賦值,我們將在記憶體中建立這一對象,並將變數a指向改對象。
第二個語句中,我們在記憶體中建立對象‘at’, 其類型是字串(string)。變數a在此又指向了'at'。而此時,對象3不再有變數指向它,Python會自動將沒有變數指向的對象銷毀(destruct),從而釋放相應記憶體。
(對於小的整數和短字串,實際上Python會緩衝這些對象,而不是針對每次賦值而分別建立和銷毀。但從邏輯層面上來說,上面的說法並沒有問題。我們將忽略這一細節)
a = 5b = aa = a + 2
再看這個例子。通過前兩個句子,我們讓a,b指向同一個整數對象5(b = a的含義是讓變數b指向變數a所指的那一個對象)。但第三個句子實際上對變數a重新賦值,讓a指向一個新的對象7。此時a,b分別指向不同的對象。我們看到,即使是多個變數指向同一個對象,如果一個變數值發生變化,那麼實際上是讓這個變數指向一個新的變數,並不影響其他的變數的指向。從效果上看,就是各個變數各自獨立,互不影響。
不止是整數如此,其它資料對象也是如此:
L1 = [1,2,3]L2 = L1L1 = 1
但注意以下情況
L1 = [1,2,3]L2 = L1L1[0] = 10print L2
在該情況下,我們不再對L1這一變數賦值,而是對L1所指向的表的元素賦值。結果是,L2也同時發生變化。
原因何在呢?因為L1,L2的指向沒有發生變化,依然指向那個表。表實際上是包含了多個變數的對象(每個變數是一個元素,比如L1[0],L1[1]..., 每個變數指向一個對象,比如1,2,3), 。而L1[0] = 10這一賦值操作,並不是改變L1的指向,而是對L1[0], 也就是表對象的一部份(一個元素),進行操作,所以所有指向該對象的變數都受到影響。
(與之形成對比的是,我們之前的賦值操作都沒有對對象自身發生作用,只是改變變數指向。)
像表這樣,可以通過引用元素,改變記憶體中的對象自身(in-place change)的物件類型,稱為可變資料對象(mutable object),詞典也是這樣的資料類型。
而像之前的數字和字串,不能改變對象本身,只能改變變數的指向,稱為不可變資料對象(immutable object)。我們之前學的定值表(tuple),儘管可以引用引用元素,但不可以通過賦值改變元素,也因此不能對對象本身進行改變,也是immutable object.
2. 從動態類型看函數的參數傳遞
函數的參數傳遞,實際上是讓函數的各個參數作為變數,指向對象。比如說:
def f(x): x = 100 print xa = 1f(a)print a
在調用函數f()時,實際上函數讓參數作為一個變數,指向a所指的對象。如果參數是不可變(immutable)的對象,那麼如上面所講,各個變數之間相當於相互獨立。參數傳遞類似於C語言中的值傳遞。
如果是參數是可變(mutable)的對象,那麼存在有改變對象自身的可能性,所有指向該對象的變數(無論是函數中的參數,還是主程式中的變數)都會受影響,編程的時候要對此問題留心。比如說:
def f(x): x[0] = 100 print xa = [1,2,3]f(a)print a
動態類型是Python的核心機制之一。可以在應用中慢慢熟悉。
總結:
變數和對象的分離,對象是記憶體中儲存資料的實體,變數指向對象。
可變對象,不可變對象
函數值傳遞