探索 Python(1): Python 的內建數值型別

發表於2015-10-23

Python 是一種敏捷的、動態型別化的、極富表現力的開源程式語言,可以被自由地安裝到多種平臺上。Python 程式碼是被解釋的。如果您對編輯、構建和執行迴圈較為熟悉,則 Python 程式碼對您來說更簡單。但是,請不要搞錯:Python 器可以是簡單的指令碼,也可以是大型的複雜程式。事實上,Python 直譯器的最大特點是鼓勵探索和簡化學習過程。如果您想證明這一點,請使用 Python 編寫著名的 Hello World! 程式:

  1. 啟動 Python 直譯器。在 UNIX 系統(包括 Mac OS X)中,啟動直譯器通常包括在命令提示行鍵入python;在 Microsoft® Windows® 系統中,啟動 Python 命令 shell。
  2. 在 Python 提示行中,在三個大於號 (>>>) 標誌後輸入 print ‘Hello World!‘,然後按 Enter
  3. 完成:沒有第三步了。清單 1 顯示了此命令的輸出。
清單 1. 用 Python 編寫的 “Hello World” 的輸出

您可以看到,我使用的是執行於 Apple OS X 系統上的 Python V2.4。但是,不管作業系統是什麼,基本原理都是一樣的,而且在本例中,所用的是 Python 的哪一個實際版本也無所謂。我雖然不瞭解您,但是此 Hello World! 練習比我學過的 C、C++ 甚至 Java™ 語言的對應練習容易多了。這種簡單性就是使用 Python 直譯器的主要優點之一。開發人員可以快速試驗一個想法、研究一種物件屬性或不同演算法,而無需編譯、執行和測試任何程式碼。

Python 型別層次結構

從其他語言過渡到 Python 程式語言時需要學習的最重要的課程之一是,Python 中的每樣東西都是物件。這一點可能並沒有什麼特別之處,尤其是對於熟悉物件導向的語言(如 C++、Java 或 C#)的人來說。然而,Python 的物件導向原理與其他語言不同,主要表現在兩個方面:第一,Python 中的所有資料值都被封裝在相關物件類中。第二,Python 程式中的所有東西都是可以從程式訪問的物件,即使是您編寫的程式碼也不例外。

大多數流行的程式語言都有多個內建的資料型別,在這一方面 Python 也一樣。例如,C 程式語言具有整型和浮點型別。由於譜系相同,Java 語言和 C# 具有內建型別也不足為奇。這意味著在 C 程式中,可以編寫 int i = 100 來建立和初始化整型變數。在 Java 和 C# 中,此方法也是可能的,而且使用它們的自動裝箱功能,在需要時這兩種語言還可以把這種簡單的內建型別轉換為 Integer 物件。

另一方面,Python 不包含像 int 這樣的簡單型別 —— 只有物件型別。如果 Python 中需要整數值,將整數賦值給相應變數(如 i = 100 )即可。在後臺,Python 將建立一個整數物件,並將對新物件的引用賦值給變數。問題的關鍵是:Python 是一種動態型別化語言,所以無需宣告變數型別。事實上在單個程式中,變數的型別是可以改變(多次)的。

一種直觀演示動態型別化工作方式的簡單方法是,設想單個名為 PyObject 的基類,讓 Python 中的所有其他物件型別都繼承它。在這一模型中,您建立的所有變數都將引用在總的類層次結構中建立的物件。如果您還讓 PyObject 類記錄曾建立並分配給變數的子類的實際型別或名稱,則 Python 程式可正確確定程式執行過程中需要採取的步驟。

上一段描述 Python 的物件導向的模型影像是對 Python 的實際工作方式很好的模擬。除此之外,Python 還可以使用型別函式來簡化對變數型別的確定。(本例還介紹如何使用帶有 # 字元的內聯註釋。)

清單 2. 演示 Python 簡單型別

可以將 PyObject 類之下的所有 Python 類劃分為 Python 執行時直譯器可以使用的四個主要類別:

  • 簡單型別 —— 基本構建塊,如 int 和 float
  • 容器型別 —— 儲存其他物件。
  • 程式碼型別 —— 封裝 Python 程式的元素。
  • 內部型別 —— 程式執行期間使用的型別。

到本系列結束時,我會把所有不同類別都介紹給大家。但是在這第一篇文章中,我重點介紹簡單型別。

簡單型別

Python 有五個內建的簡單型別:boolintlongfloat 和 complex。這些型別是不可變的,就是說整數物件一旦建立,其值便不可更改。相反,系統將建立新的簡單型別物件並將其賦值給變數。通過 Python id 函式,可以檢視基本 PyObject 標識的變更方式:

清單 3. 使用 Python id 函式

此方法看似容易丟失物件,會導致記憶體洩漏。但是,Python 像 C# 和 Java 一樣,使用了垃圾回收功能,以釋放用於儲存不再引用的物件的記憶體,如上例中用於儲存 100 的整數物件。

布林型別

Python 中最簡單的內建型別是 bool 型別,該型別包括的物件僅可能為 True 或 False

清單 4. bool 型別

因為只有兩個可能值,所以布林型別是惟一的。Python 直譯器提供這僅有的(也是必需的)兩個 bool 物件:True 和 False。在任何時候,在 Python 程式需要這些物件時,變數只能相應地引用其中一個值。清單 5 顯示 bb 變數如何具有同一個 id,不管您直接賦予它 b 變數的值還是直接賦予它 True 物件。

清單 5. bb 變數的值

布林物件名稱的大小寫是至關重要的,因為 true(和 false)是未定義的:

清單 6. 未定義的 true 和 false

在這一點上,bool 型別可能看起來不是很有用。不過顧名思義,布林表示式是依賴於名稱的,如下所示:

清單 7. 布林表示式

很多程式利用布林表示式,Python 提供一整套布林比較和邏輯運算,詳細資訊請分別參見表 1 和表 2。

表 1. Python 中的布林比較運算子
運算子 描述 示例
< 小於 i < 100
<= 小於等於 i <= 100
> 大於 i > 100
>= 大於等於 i >= 100
== 相等 i == 100
!= 不相等(另外使用 <>) i != 100

補充一點,表 1 中列出的運算子優先順序都一樣,除非將表示式置於括號中,否則按從左到右的順序應用。

表 2. Python 中的邏輯運算子
運算子 描述 示例
not 邏輯非 not b
and 邏輯與 (i <= 100) and (b == True)
or 邏輯或 (i < 100) or (f > 100.1)

邏輯運算子的優先順序低於單獨的比較運算子,這一點意義重大,因為必須先計算比較運算子,然後才能計算邏輯運算子。邏輯運算子的實際優先順序就是表 2 中羅列這些運算子的順序。

在 Python 中,關於 or 和 and 邏輯運算子有意思的是,它們都是快捷運算子。簡言之,如果給定表示式 x or y,則僅當 x 為 False 時才會計算 y。同樣地,如果給定表示式 x and y,則僅當 x 為 True 時,才會計算 y。此功能可以增強表示式求值的效能(尤其是針對長的或複雜的表示式),然而對於習慣於從其他語言學來的不同規則的程式設計師而言,則容易犯錯。

數值型別

Python 中其他四個簡單的內建型別都是數值型別:intlongfloat 和 complex。在程式中,數值型別很常見,不管使用的是什麼語言。Python 對算術運算提供完整支援,包括加法、減法、乘法和除法(參見表 3)。

表 3. Python 中的算術運算
運算子 描述 示例
* i * 100
/ i / 100
// 整除 i // 100
% 取餘 f % 100
+ i + 100
i - 100

乘法和除法運算子(表 3 中列出的前四個)具有高於加法和減法的優先順序。如前所述,您可以通過使用括號分組子表示式,將其分離出來以提高優先順序。

Python 與 Java 語言不同,Java 語言通常定義允許的數值型別的範圍,而 Python 在這一點上更像 C,因為它的型別範圍是依賴於平臺的。您可以使用 int 和 long 兩種型別來儲存整數值,它們的不同點在於 int 是一種 32 位的整數值。因而,它被限制為只能儲存從 -232 到 232 – 1 之間的值(在多數平臺上)。與此相反,長整數型別的精度不受限,僅計算機記憶體對它有影響。要通知 Python 應該按照長型別處理整數,只需將 L附加到數字的末尾,如 100L。在 Python 中,浮點值始終是按雙精度處理的;因此 Python 的 float 型別對應於 C 類語言中的雙精度。

與數值型別相關的其他兩個重點是常量(如上例中的 100,只是明確表達的數字)和位運算。程式設計師一般在十進位制系統(以 10 為基數)中工作。但是,有時其他系統也相當有用,尤其是我們知道計算機是基於二進位制的。Python 可以提供對八進位制(以 8 為基數)和十六進位制(以 16 為基數)數字的支援。要通知 Python 應該按八進位制數字常量處理數字,只需將零附加在前面。將一個零加上一個 x 附加在數字的前面是告訴 Python 按十六進位制數值常量處理數字,如以下程式碼所示:

清單 8. 通知 Python 按十六進位制數值常量處理數字

當您具有容易的方式來表達數值常量時,尤其是十六進位制,就可以容易地構建對應於特定測試用例的標誌,這是一種常見的程式設計技術。例如,一個 32 位的整數可以儲存 32 個標誌值。使用位測試,可以容易地測試標誌變數上的特定標誌。Python 中位運算的完整列表如表 4 所示。

表 4. Python 中的位運算
運算子 描述 示例
~ 按位求補 ~b
<< 向左位移 b << 1
>> 向右位移 b >> 1
& 按位和 b & 0x01
^ 按位異或 b ^ 0x01
| 按位或 b | 0x01

至此,您可能想知道不同數值型別在單個表示式中混合出現的時候怎麼辦。簡單的答覆是,Python 會根據需要將表示式中的所有運算元轉換為最複雜的運算元的型別。複雜度的順序是:intlongfloat 和 complex(非雙關),下面是一個簡單的示例:

清單 9. Python 將所有運算元轉換為最複雜的運算元

儘管 Python 會與您預期的一樣轉換運算元,但是語言並不基於運算子轉換運算元,如 1/3 示例中所示,其計算結果為整數。如果要強制取得浮點結果,則必須確保運算元中至少有一個為浮點型別。

complex 型別

最後一種型別 complex 可能是大多數程式設計師難以識別的,因為它不是其他程式語言中常見的內建資料型別。而對於工程師和科學家來說,複數卻是個司空見慣的概念。從形式上講,複數 具有實部和虛部兩個部分,都由 Python 中的 float 型別來表示。虛數 是 -1 的平方根的倍數,用 i或 j 表示 —— 取決於您被培養為科學家還是工程師。在 Python 中,複數的虛部被表示為 j

清單 10. 複數的虛部

本例是一個實部為 3.0 和虛部為 1.2 的複數。注意,通過使用複雜物件的 real 和 imag 屬性,即可訪問複數的不同部分。

它們真是物件嗎?

到此為止,我已經介紹了 Python 只處理物件型別,然而示例中好像並沒有什麼物件。最後還有一個問題,建構函式在哪裡?對於簡單的內建資料型別,Python 替您做了大量的工作。不過,建構函式還在那裡(其名稱與相關資料型別的名稱相同),如果您願意,可以直接使用它們,如下所示:

清單 11. Python 建構函式

結束語

Python 是一種無比簡單又功能強大的語言。入門極其容易,尤其是對於已經具有 C 類語言的經驗的程式設計師來說。本文簡單介紹了 Python 程式語言和內建資料型別:boolintlongfloat 和 complex。如果您尚未理解,則請啟動一個 Python 直譯器,並嘗試按照我上面討論的方法操作。您將會很高興,我做到的您也可以做到。

相關文章