《Abaqus GUI程序开发指南(Python语言)》——2.5 动态类型简介
本節書摘來自異步社區《Abaqus GUI程序開發指南(Python語言)》一書中的第2章,第2.5節,作者: 賈利勇 , 富琛陽子 , 賀高 , 周正光 更多章節內容可以訪問云棲社區“異步社區”公眾號查看。
2.5 動態類型簡介
前面講述了Python中常用的數據類型,可以看出,在Python語言中使用變量時,都沒有聲明變量的存在以及類型,但變量還可以工作。這一點與靜態編譯語言C、C++或Java有很大的區別。這就是Python語言的動態類型模型。
在Python語言中,數據類型是在運行過程中自動決定的,而不是通過代碼聲明。變量在賦值的時候才被創建,它可以引用任何類型的對象,變量和對象分別存儲在內存中的不同位置,兩者通過鏈接進行關聯。
對于下列代碼:
>>>a=5Python將會執行3個不同的步驟去完成這個請求,這些步驟反映了Python語言中所有賦值的操作過程。
(1)創建一個新對象來代表數字5。
(2)創建一個變量a。
(3)將變量a與新對象a相關聯。
在Python中從變量到對象的鏈接稱作引用。也就是說,引用是一種關系,以內存中的指針形式實現。一旦變量被使用(也就是被引用),Python自動跟隨這個變量到對象的鏈接。
2.5.1 類型的歸屬
在Python語言中,類型屬于對象,不屬于變量,我們可以對一個變量進行多次賦值,且允許每次賦值的類型不同,例如:
【實例2.20】單變量多次賦值
>>>a=5 #將變量a與整型對象關聯 >>>a='five' #將變量a與字符串型對象關聯 >>>a=5.0 #將變量a與浮點型對象關聯上述代碼中,變量a一開始是整型,然后變成一個字符串,最后變成了浮點數。這一點,在C語言中是無法理解的。但是在Python中,理解起來就很簡單,因為變量名根本沒有類型。實際上Python的變量就是在特定的時間引用了一個特定的對象,而對象是具有類型的,每個對象都包含了一個頭部信息,其中標記了對象的類型。
可以看出,Python代碼比通常慣用的代碼更加靈活,如果能正確地使用Python,代碼能夠自動以多種類型進行工作。
2.5.2 垃圾回收機制
在實例2.20中,當重新給變量a賦值時,它前一個引用對象是會發生變化的。在Python中,每當一個變量名被賦予了一個新的對象時,且之前的那個對象沒有被其他變量名或對象所引用的話,那么之前的那個對象占用的空間就會被回收,這種自動回收對象占用空間的技術叫作垃圾回收。
在Python內部,垃圾回收是如何實現的呢?實際上,每個對象中都保持了一個計數器,計數器記錄了當前指向該對象的引用次數,也就是該對象被引用的次數。一旦這個計數器被設置為零,這個對象的內存空間就會被自動回收。
垃圾回收最直接且可感受的好處就是,可以在腳本中任意使用該對象而不需要考慮釋放內存空間。與C和C++這樣的底層語言相比,省去了大量基礎代碼。
2.5.3 共享引用及原處修改
首先看一個兩個變量的重復賦值實例。
【實例2.21】
>>> a=5 >>> b=a >>> a,b (5, 5)該實例中,第一行創建了對象5,并將變量a與之關聯,第二行創建了變量b,變量b也成為對象5的一個引用。實際上,變量a和變量b都引用了相同的對象,都指向了相同的內存空間,這在Python語言中叫作共享引用——多個變量名引用同一對象。
對上述代碼做如下修改:
>>> a=5 >>> b=a >>> a ='five' >>> a,b ('five', 5)第三行代碼創建了一個新的對象'five',并設置a對這個新的對象進行引用,而b仍然繼續引用之前的對象5。
與其他語言不同,在Python中,給一個變量賦一個新的值,并不是替換了原始的對象,而是重新創建一個不同的對象,并讓這個變量去引用這個新的對象。實際效果就是,對一個變量賦值,僅僅會影響被賦值的變量。
但是,也有一些特殊的情況,當引用一些可變對象時,在原處對對象進行修改時,就會出現不一樣的情況。例如,在一個列表中對某一個偏移位置進行重新賦值時,會改變這個列表對象,而不是生成一個新的對象。首先看一個容易理解的實例:
【實例2.22】
>>> a=[1,2,3] >>> b=a >>> a [1, 2, 3] >>> b [1, 2, 3] >>> a=999 >>> a 999 >>> b [1, 2, 3]由程序執行結果可以看出,上述實例中一開始變量a和b都引用了列表對象[1,2,3],后來當對a重新賦值后,創建了新的對象999,并讓a引用了這個新的對象,整個過程中b并沒有發生變化,這與前面的實例類似,同屬于共享引用的范疇。
然而,列表中的元素都是通過其索引位置進行讀取的,例如:
>>> a=[1,2,3] >>> b=a >>> a[0],a[1],a[2] (1, 2, 3)其中,a[0]引用的是對象1,a[1]引用的是對象2,a[2]引用的是對象3。當然,列表自身也是一個對象,接下來對上述代碼做一下簡單的修改,就會出現明顯不同的結果。
【實例2.23】
>>> a=[1,2,3] #創建列表對象[1,2,3]和變量a,并讓a引用該對象 >>> b=a #創建變量b,并讓b引用同一列表對象 >>> a [1, 2, 3] >>> b [1, 2, 3] #變量a和b數值相同 >>> a[0]='one' #修改變量所引用的對象的一個元素 >>> a ['one', 2, 3] #變量a數值發生變化 >>> b ['one', 2, 3] #變量b數值也發生變化在上述程序中,我們沒有改變a,只是改變了a所引用對象的一個元素,這類修改會覆蓋列表對象中的某些部分,它不僅僅會影響變量a,也會同時影響變量b,因為它們引用的是同一個列表對象。對于這種在原處修改的對象,共享引用時需要加倍小心,不注意的話非常容易出錯。
如果不希望上述情況出現時,需要使用Python的對象復制,而不是創建引用。Python有多種復制列表的方法,現列舉如下。
【實例2.24】列表對象復制
>>> a=[1,2,3] >>> b=a[:] #復制列表 >>> a [1, 2, 3] >>> b [1, 2, 3] >>> a[0]=999 >>> a [999, 2, 3] >>> b [1, 2, 3] #a引用的列表中某一元素變化時,b未改變。這種情況下,對a的修改不會影響b,因為b引用的是a所引用對象的復制,兩個變量指向了不同的內存區域。需要注意的是,這種分片技術不能用于集合和字典等非序列類型的對象中。
除了上述復制方法之外,還可以使用copy()函數實現,例如:
【實例2.25】copy()函數
>>> import copy >>> a=[1,2,3] >>> b=copy.copy(a) >>> b [1, 2, 3] >>> a[0]=999 >>> a [999, 2, 3] >>> b [1, 2, 3]另外,需要注意的是,copy()函數可以用于集合或者字典等無序的對象類型中。
**
2.5.4 共享引用和相等**
由于Python的引用機制,在Python程序中有兩種不同的方法去檢查兩個變量是否相等,以下面的共享引用來說明。
【實例2.26】
>>> a=[1,2,3] >>> b=a >>> a==b True >>> a is b True上述代碼中,第一種判斷方法是采用“==”操作符,測試兩個變量所引用的對象是否有相同的值。第二種方法“is”操作符,是檢查對象的同一性,如果兩個變量a和b均指向同一個對象,它會返回True,所以這是一種更嚴格的相等測試。如果兩個變量名引用的對象值相等,但是是不同的對象,那么在使用“is”操作符進行判斷時,它會返回False,例如:
【實例2.27】
>>> a=[1,2,3] >>> b=[1,2,3] >>> a==b True >>> a is b False上面的代碼中,第一行創建了一個列表對象[1,2,3]和變量a,并將變量a與之關聯,第二行又創建了一個列表對象[1,2,3]和變量b,變量a和b引用的對象數值相同,卻不是同一個對象。
另外,需要特別注意的就是,當我們對小的數字采用上述同樣的操作時,返回的結果會有所不同,例如:
【實例2.28】
>>> a=1 >>> b=1 >>> a==b True >>> a is b True為什么這組測試的結果和實例2.27測試的結果互相矛盾呢?原因就是,對于小的整數和字符串,Python會將其緩存并復用,所以在本實例中才會出現a和b引用的是同一個對象的現象。
如果讀者想弄清楚一個對象被引用的次數的話,可以使用sys模塊下的getrefcount函數來查詢一個對象被引用的次數。例如:
>>> import sys >>> sys.getrefcount(1) 1044 >>> sys.getrefcount(5) 91總結
以上是生活随笔為你收集整理的《Abaqus GUI程序开发指南(Python语言)》——2.5 动态类型简介的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《JavaScript忍者秘籍》——导读
- 下一篇: 《短文本数据理解(1)》一1.3 短文本