天天看點

《Abaqus GUI程式開發指南(Python語言)》——2.5 動态類型簡介

本節書摘來自異步社群《abaqus gui程式開發指南(python語言)》一書中的第2章,第2.5節,作者: 賈利勇 , 富琛陽子 , 賀高 , 周正光 更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

前面講述了python中常用的資料類型,可以看出,在python語言中使用變量時,都沒有聲明變量的存在以及類型,但變量還可以工作。這一點與靜态編譯語言c、c++或java有很大的差別。這就是python語言的動态類型模型。

在python語言中,資料類型是在運作過程中自動決定的,而不是通過代碼聲明。變量在指派的時候才被建立,它可以引用任何類型的對象,變量和對象分别存儲在記憶體中的不同位置,兩者通過連結進行關聯。

對于下列代碼:

python将會執行3個不同的步驟去完成這個請求,這些步驟反映了python語言中所有指派的操作過程。

(1)建立一個新對象來代表數字5。

(2)建立一個變量a。

(3)将變量a與新對象a相關聯。

在python中從變量到對象的連結稱作引用。也就是說,引用是一種關系,以記憶體中的指針形式實作。一旦變量被使用(也就是被引用),python自動跟随這個變量到對象的連結。

2.5.1 類型的歸屬

在python語言中,類型屬于對象,不屬于變量,我們可以對一個變量進行多次指派,且允許每次指派的類型不同,例如:

【執行個體2.20】單變量多次指派

上述代碼中,變量a一開始是整型,然後變成一個字元串,最後變成了浮點數。這一點,在c語言中是無法了解的。但是在python中,了解起來就很簡單,因為變量名根本沒有類型。實際上python的變量就是在特定的時間引用了一個特定的對象,而對象是具有類型的,每個對象都包含了一個頭部資訊,其中标記了對象的類型。

可以看出,python代碼比通常慣用的代碼更加靈活,如果能正确地使用python,代碼能夠自動以多種類型進行工作。

2.5.2 垃圾回收機制

在執行個體2.20中,當重新給變量a指派時,它前一個引用對象是會發生變化的。在python中,每當一個變量名被賦予了一個新的對象時,且之前的那個對象沒有被其他變量名或對象所引用的話,那麼之前的那個對象占用的空間就會被回收,這種自動回收對象占用空間的技術叫作垃圾回收。

在python内部,垃圾回收是如何實作的呢?實際上,每個對象中都保持了一個計數器,計數器記錄了目前指向該對象的引用次數,也就是該對象被引用的次數。一旦這個計數器被設定為零,這個對象的記憶體空間就會被自動回收。

垃圾回收最直接且可感受的好處就是,可以在腳本中任意使用該對象而不需要考慮釋放記憶體空間。與c和c++這樣的底層語言相比,省去了大量基礎代碼。

2.5.3 共享引用及原處修改

首先看一個兩個變量的重複指派執行個體。

【執行個體2.21】

該執行個體中,第一行建立了對象5,并将變量a與之關聯,第二行建立了變量b,變量b也成為對象5的一個引用。實際上,變量a和變量b都引用了相同的對象,都指向了相同的記憶體空間,這在python語言中叫作共享引用——多個變量名引用同一對象。

對上述代碼做如下修改:

第三行代碼建立了一個新的對象'five',并設定a對這個新的對象進行引用,而b仍然繼續引用之前的對象5。

與其他語言不同,在python中,給一個變量賦一個新的值,并不是替換了原始的對象,而是重新建立一個不同的對象,并讓這個變量去引用這個新的對象。實際效果就是,對一個變量指派,僅僅會影響被指派的變量。

但是,也有一些特殊的情況,當引用一些可變對象時,在原處對對象進行修改時,就會出現不一樣的情況。例如,在一個清單中對某一個偏移位置進行重新指派時,會改變這個清單對象,而不是生成一個新的對象。首先看一個容易了解的執行個體:

【執行個體2.22】

由程式執行結果可以看出,上述執行個體中一開始變量a和b都引用了清單對象[1,2,3],後來當對a重新指派後,建立了新的對象999,并讓a引用了這個新的對象,整個過程中b并沒有發生變化,這與前面的執行個體類似,同屬于共享引用的範疇。

然而,清單中的元素都是通過其索引位置進行讀取的,例如:

其中,a[0]引用的是對象1,a[1]引用的是對象2,a[2]引用的是對象3。當然,清單自身也是一個對象,接下來對上述代碼做一下簡單的修改,就會出現明顯不同的結果。

【執行個體2.23】

在上述程式中,我們沒有改變a,隻是改變了a所引用對象的一個元素,這類修改會覆寫清單對象中的某些部分,它不僅僅會影響變量a,也會同時影響變量b,因為它們引用的是同一個清單對象。對于這種在原處修改的對象,共享引用時需要加倍小心,不注意的話非常容易出錯。

如果不希望上述情況出現時,需要使用python的對象複制,而不是建立引用。python有多種複制清單的方法,現列舉如下。

【執行個體2.24】清單對象複制

這種情況下,對a的修改不會影響b,因為b引用的是a所引用對象的複制,兩個變量指向了不同的記憶體區域。需要注意的是,這種分片技術不能用于集合和字典等非序列類型的對象中。

除了上述複制方法之外,還可以使用copy()函數實作,例如:

【執行個體2.25】copy()函數

另外,需要注意的是,copy()函數可以用于集合或者字典等無序的對象類型中。

**

2.5.4 共享引用和相等**

由于python的引用機制,在python程式中有兩種不同的方法去檢查兩個變量是否相等,以下面的共享引用來說明。

【執行個體2.26】

上述代碼中,第一種判斷方法是采用“==”操作符,測試兩個變量所引用的對象是否有相同的值。第二種方法“is”操作符,是檢查對象的同一性,如果兩個變量a和b均指向同一個對象,它會傳回true,是以這是一種更嚴格的相等測試。如果兩個變量名引用的對象值相等,但是是不同的對象,那麼在使用“is”操作符進行判斷時,它會傳回false,例如:

【執行個體2.27】

上面的代碼中,第一行建立了一個清單對象[1,2,3]和變量a,并将變量a與之關聯,第二行又建立了一個清單對象[1,2,3]和變量b,變量a和b引用的對象數值相同,卻不是同一個對象。

另外,需要特别注意的就是,當我們對小的數字采用上述同樣的操作時,傳回的結果會有所不同,例如:

【執行個體2.28】

為什麼這組測試的結果和執行個體2.27測試的結果互相沖突呢?原因就是,對于小的整數和字元串,python會将其緩存并複用,是以在本執行個體中才會出現a和b引用的是同一個對象的現象。

如果讀者想弄清楚一個對象被引用的次數的話,可以使用sys子產品下的getrefcount函數來查詢一個對象被引用的次數。例如: