動(dòng)態(tài)類型(dynamic typing)是Python另一個(gè)重要的核心概念尚困。我們之前說過,Python的變量(variable)不需要聲明贝奇,而在賦值時(shí)芝此,變量可以重新賦值為任意值。這些都與動(dòng)態(tài)類型的概念相關(guān)寿酌。
動(dòng)態(tài)類型
在我們接觸的對(duì)象中胰苏,有一類特殊的對(duì)象,是用于存儲(chǔ)數(shù)據(jù)的醇疼。常見的該類對(duì)象包括各種數(shù)字硕并,字符串,表秧荆,詞典倔毙。在C語言中,我們稱這樣一些數(shù)據(jù)結(jié)構(gòu)為變量乙濒。而在Python中陕赃,這些事對(duì)象。
對(duì)象是儲(chǔ)存在內(nèi)存中的實(shí)體颁股。膽我們并不能直接接觸到該對(duì)象么库。我們?cè)诔绦蛑袑懭氲膶?duì)象名,只是指向這一對(duì)象的引用(reference)甘有。
引用和對(duì)象分離诉儒,是動(dòng)態(tài)類型的核心。引用可以隨時(shí)指向一個(gè)新的對(duì)象:
a = 3
a = 'at'
第一個(gè)語句中亏掀,3是儲(chǔ)存在內(nèi)存中的一個(gè)整數(shù)對(duì)象忱反。通過賦值泛释,引用a指向?qū)ο?。
第二個(gè)語句中缭受,內(nèi)存中建立對(duì)象'at'胁澳,是一個(gè)字符串(string)。引用a指向了'at'米者。此時(shí)韭畸,對(duì)象3不再有引用指向它。Python會(huì)自動(dòng)將沒有引用指向的對(duì)象銷毀(destruct)蔓搞,釋放相應(yīng)內(nèi)存胰丁。
(對(duì)于小的整數(shù)和短字符串,Python會(huì)緩存這些對(duì)象喂分,而不是頻繁的建立和銷毀锦庸。)
a = 5
b = a
a = a + 2
再看這個(gè)例子。通過前兩個(gè)句子蒲祈,我們讓a,b指向同一個(gè)整數(shù)對(duì)象5(b = a的含義是讓引用b指向引用a所指的那一個(gè)對(duì)象)甘萧。但第三個(gè)句子實(shí)際上對(duì)引用a重新賦值,讓a指向一個(gè)新的對(duì)象7.此時(shí)a,b分別指向不同的對(duì)象梆掸。我們看到扬卷,即使是多個(gè)引用指向同一個(gè)對(duì)象,如果一個(gè)引用值發(fā)送變化酸钦,那么實(shí)際上是讓這個(gè)引用指向一個(gè)新的引用怪得,并不影響其他的引用的指向。從效果上看卑硫,就是各個(gè)引用各自獨(dú)立徒恋,互不影響。
其它數(shù)據(jù)對(duì)象也是如此:
L1 = [1,2,3]
L2 = L1
L1 = 1
但注意以下情況
L1 = [1,2,3]
L2 = L1
L1[0] = 10
print L2
在該情況下欢伏,我們不再對(duì)L1這一引用賦值入挣,而是對(duì)L1所指向的表的元素賦值。結(jié)果是硝拧,L2也同時(shí)發(fā)生變化财岔。
原因何在呢?因?yàn)長1河爹,L2的指向沒有發(fā)送變化匠璧,依然指向那個(gè)表。表實(shí)際上市包含了多個(gè)引用的對(duì)象(每個(gè)引用是一個(gè)元素咸这,比如L1[0]夷恍,L1[1]...,每個(gè)引用指向一個(gè)對(duì)象,比如1,2,3酿雪,遏暴。而L1[0] = 10這一賦值操作,并不是改變L1的指向指黎,而是對(duì)L1[0]朋凉,也就是表對(duì)象的一部分(一個(gè)元素),進(jìn)行操作醋安,所以所有指向該對(duì)象的引用都受到影響杂彭。
(與之形成對(duì)比的是,我們之前的賦值操作都沒有對(duì)對(duì)象自身發(fā)生作用吓揪,只是改變引用指向亲怠。)
列表可以通過引用其元素,改變對(duì)象自身(in-place change)柠辞。這種對(duì)象類型团秽,稱為可變數(shù)據(jù)對(duì)象(mutable object),詞典也是這樣的數(shù)據(jù)類型叭首。
而像之前的數(shù)字和字符串习勤,不能改變對(duì)象本身,只能改變引用的指向焙格,稱為不可變數(shù)據(jù)對(duì)象(immutable object)**姻报。
我們之前學(xué)的元組(tuple),盡管可以調(diào)用引用元素间螟,但不可以賦值,因此不能改變對(duì)象自身损肛,所以也算是immutable object厢破。
從動(dòng)態(tài)類型看函數(shù)的參數(shù)傳遞
函數(shù)的參數(shù)傳遞,本質(zhì)上傳遞的是引用治拿。比如說:
def f(x):
x = 100
print x
a = 1
f(a)
print a
參數(shù)x是一個(gè)新的引用摩泪,指向a所指的對(duì)象。如果參數(shù)是不可變(immutable)的對(duì)象劫谅,a和x引用之間相互獨(dú)立见坑。對(duì)參數(shù)x的操作不會(huì)影響引用a。這樣的傳遞類似于C語言中的值傳遞捏检。
如果傳遞的是可變(mutable)的對(duì)象荞驴,那么改變函數(shù)參數(shù),有可能改變?cè)瓕?duì)象贯城。所有指向原對(duì)象的引用都會(huì)受影響熊楼,編程的時(shí)候要對(duì)比問題留心。比如說:
def f(x):
x[0] = 200
print x
a = [1,2,3]
f(a)
print a
動(dòng)態(tài)類型是Python的核心機(jī)制之一能犯■昶可以在應(yīng)用中慢慢熟悉犬耻。
總結(jié)
引用和對(duì)象的分離,對(duì)象是內(nèi)存中儲(chǔ)存數(shù)據(jù)的實(shí)體执泰,引用指向?qū)ο蟆?br>
可變對(duì)象枕磁,不可變對(duì)象
函數(shù)值傳遞