天天看點

《從問題到程式:用Python學程式設計和計算》——2.2 資料對象、計算和類型

本節書摘來自華章計算機《從問題到程式:用python學程式設計和計算》一書中的第2章,第2.2節,作者:裘宗燕 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

前面介紹了python中可以表示和處理的幾種數——整數、浮點數和複數,它們都是數學裡的某類數的對應物,可以對它們做各種數學運算(用運算符描述),得到運算的結果。這些數都是程式操作的對象。

2.2.1 對象和類型

雖然整數、浮點數都是數,可以使用同樣的運算符,但對數值相同的整數和浮點數做同樣計算時,由于采用的規則不同,得到的結果也不同。例如:

整數計算将得到任意大的準确結果,浮點數計算得到有限精度的近似結果 。

python語言把在程式運作中能使用和處理的各種實體統稱為對象(object),一個整數是一個對象,一個浮點數也是一個對象。在處理整數或浮點數字面量時,解釋器建立相應的整數對象或浮點數對象,而計算也就是從一些對象算出另一些對象。在互動方式下,解釋器把計算得到的結果對象顯示出來給人看。

不同對象可能具有不同的性質。python把性質相同、可以使用同一組操作、采用同樣計算規則的一集對象稱為一個類型。對屬于同一類型的對象,解釋器采用同樣的處理方式。例如,整數就是一個類型,浮點數是另一個類型,複數又是另一個不同的類型。這幾個類型有各自的字面量寫法、可用運算的集合和運算規則。人們經常把整數類型簡稱為整型,把浮點數類型簡稱為浮點型。後面有時也這樣說。

python中的每個類型有一個名字(類型名),可以用特殊的方法得到:

第一個結果 表示字面量100描述的整數對象屬于名字為int的類型,其他結果的意義類似。每個類型都有一個名字,稱為類型名。整數類型的名字是int,浮點數的類型名是float,而複數的類型名是complex。對于任何描述對象的表達式,都可以用type取得其計算結果的類型:

int、float和complex統稱為數值類型(numerical type)。這幾個數值類型都是python語言預先定義的類型,稱為内置類型或者标準類型。

2.2.2 混合類型計算和類型轉換

對數值類型的對象,python允許做混合類型計算,也就是說,允許在一個表達式裡出現不同數值類型的對象。例如:

自然,最後一個表達式得到的是複數類型的結果(對象)。

整數和浮點數各有自己的乘法運算規則,兩者的運算規則不同。為了完成兩個不同類型的對象之間的運算,python嚴格規定了采用的規則。在這裡的規定是:如果遇到表達式要求做一個整數和一個浮點數的運算,那麼就先從那個整數轉換得到一個“與之等值”的浮點數對象,而後再按浮點數的規則計算,得到浮點數結果。如果是整數(或浮點數)與複數運算,就先從該數轉換得到一個複數,然後再計算。注意,這裡說轉換,術語是類型轉換,實際上原來的數并不改變,而是根據該數按規則做出另一個滿足需要的數。

上面的“與之等值”加了引号,是想說明這個說法并不準确。整數可以任意大,具有任意位精度。用浮點數表示,或許能表示其近似值(是以并不與之等值),甚至無法表示它(由于整數太大而溢出)。這是混合類型計算中可能出現的情況,必須注意。

總結一下:對混合類型的計算表達式,python解釋器将自動安排适當的轉換,使表達式描述的計算得以進行。這種轉換是解釋器自動完成的操作,從已有的某類型對象出發,做出一個與之相關的具有所需類型的對象。在上面第二個例子裡,先根據2做出一個複數,再用它與複數(1+3.4j)相加;再從整數3做出一個浮點數并從5.78裡減去它;再從第二個計算的結果(一個浮點數)做出一個複數并完成兩個複數的乘法。可見,要了解複雜表達式的意義,不僅要關注其中的計算如何進行,還要注意哪些地方出現了類型轉換,各為從什麼類型轉到什麼類型,具體計算是在哪個類型裡進行的。

有時,自動完成的轉換不符合實際計算的需要。出現這種情況時,我們就需要在表達式裡說明期望的轉換,相應描述稱為強制類型轉換。強制類型轉換通過類型名描述,描述形式與前面寫type的形式類似。例如:

這裡int(2.37**5.6)要求把浮點數計算的結果轉換為整數,然後用它乘以4得到整數結果。用int将浮點數轉換到整數的規則是丢掉小數,取得整數部分。

如果寫表達式float(12**20),可以得到括号裡整數計算結果的浮點數近似值。但python不允許用float或int去轉換複數對象,數學裡也沒有相應的規則。如果對不能轉換的對象做轉換,解釋器也會報告錯誤。例如:

取得複數的實部、虛部或者模的問題在後面說明。

類型名complex可用于構造複數:

括号裡逗号分隔的兩個表達式分别表示要構造的複數的實部和虛部。

最後考慮一個實際應用題:已知三角形的三邊長度分别為5、7和11厘米,現在希望求出這個三角形的面積。

顯然,為完成這個任務,首先需要找到從三邊長求面積的方法。數學知識已經給出了相應的面積公式:

《從問題到程式:用Python學程式設計和計算》——2.2 資料對象、計算和類型

其中s是三角形的半周長, 。根據這些公式,不難寫出下面表達式:

為了寫出這個長表達式,我們特别在前面多寫了一個括号。在表達式換行時,因為有括号沒配對,解釋器自動把後一行當作續行。顯然,這個表達式雖然解決了問題,但其形式不太令人滿意,其中出現繁瑣的重複。2.5節将解決這個問題。

2.2.3 數值類型和計算的簡單總結

現在對本章中至此有關數值類型計算的讨論做一點總結。

python語言提供了三個基本數值類型:int、float和comlex,規定了各種數字面量的描述形式,以便人們直接描述計算中使用的數值對象。python的整數對象可以表示任意大的整數值,但浮點數(和複數)隻能表示有限範圍内精度有限的數值。

表示數值計算的表達式基于數值字面量、算術運算符和括号描述,形式上是一維的單詞序列,序列中的單詞和序列的構成形式都必須滿足表達式的文法要求。滿足規定(滿足文法)的表達式才有意義(語義)。python嚴格規定了單詞和表達式的形式,所采用的形式解釋器容易處理,人可以接受和習慣。遇到不合法的單詞,或者構成形式不合法的表達式,解釋器将報錯,并能标明發現錯誤的位置。

合法的表達式描述了一個計算過程。如果解釋器處理一個表達式的計算能順利完成,就會求出該表達式的值。但是,滿足文法的表達式在計算中也可能出錯,如3/0、3.0/0.0在計算中就會報告除以0的動态運作錯誤。此外,浮點數運算的結果可能超出浮點數的表示範圍,這種情況稱為溢出。出現溢出時得到一個特殊結果。

表達式描述的求值過程由多方面的因素确定:運算符有優先級和結合方式,高優先級的運算符先執行,相同優先級的運算符按結合順序執行。如果由優先級和結合方式預設确定的計算順序不合适,可以加入括号明确指定所需計算順序。

算術運算符分為一進制運算符(正負号)和二進制運算符,對二進制運算符,在做它所要求的計算之前,總是先計算其左邊的運算對象,再計算右邊的運算對象。

參與計算的對象都有類型,計算的結果也有類型,對象的類型決定計算的方式和結果。兩個同樣類型的數值對象直接參與運算,運算結果一般也具有同樣類型(整數除法運算符 / 的情況特殊,其結果是浮點數)。用type可以得到表達式的計算結果的類型(注意,字面量是最簡單的表達式)。

如果參與一個二進制運算的兩個對象的類型不同,解釋器先把它們轉換為同樣類型後再計算。整數與浮點數或複數運算,解釋器自動由它做出一個浮點數或複數;浮點數與複數運算,解釋器自動由這個浮點數做出一個複數。如果混合類型計算中的自動轉換不合乎需要,可以人工描述轉換。用類型名int可以構造與給定浮點數對應的整數值(取整)。

應特别注意,做數值轉換時可能出錯。在把一個整數轉換為一個浮點數時,得到的結果可能超出浮點數的表示範圍。還需注意,整數計算是精确計算,總得到精确的整數結果(除了使用運算符 / 的情況),浮點數計算和複數計算是近似計算,總得到近似結果,計算中可能出現誤差,需要特别當心。這個問題後面還會讨論。