Python 資料全景課 / 第二部分 Python 基礎 · M3

M3 值與型別

書價 120、庫存 3、有沒有現貨、還沒填的電郵:它們在 Python 裏是不同「型別」的值。型別決定了一個值能做甚麼;弄錯型別,是讀入資料後最常見的錯誤。
約 45 分鐘練習 notebook 1 個先修:M2
學完本單元,你能夠:
  1. 認出 int、float、str、bool、None 五種值,並用 type() 查出一個值的型別;
  2. 說出 "120" 和 120 的分別,以及各自能做甚麼運算;
  3. 用 int()、float()、str() 轉換型別,並看懂轉換失敗時的錯誤訊息;
  4. 理解變數只是貼在值上的名字。

1每個值都有型別 Every value has a type

M0 那本書的資料,讀入 Python 之後,每一個值都有自己的型別(type):

圖 1 M0 的書讀入 Python 後,每個值的型別。JSON 和 YAML 裏的寫法,決定了讀入後是哪一種型別。
圖 1 M0 的書讀入 Python 後,每個值的型別。JSON 和 YAML 裏的寫法,決定了讀入後是哪一種型別。

用 type() 可以查出一個值的型別:

type(120)        # <class 'int'>
type(120.0)      # <class 'float'>
type("120")      # <class 'str'>
type(True)       # <class 'bool'>
type(None)       # <class 'NoneType'>

這一單元講這五種最基本的值。list 和 dict 這兩種容器留待 M4。

型別 中文 例子 JSON 的寫法
int 整數 120、-3、0 120
float 浮點數(有小數) 21.5、0.8、120.0 21.5
str 字串(文字) "看得見的資料"、"120" "120"
bool 布林值(是/否) True、False true、false
NoneType 沒有值 None null

2數字:int 和 float Numbers: int and float

數字有兩種:沒有小數點的是 int,有小數點的是 float。120 和 120.0 數值相等,型別卻不同。

運算 例子 結果 說明
+ - * 120 * 3 360 加減乘
/ 7 / 2、6 / 2 3.5、3.0 除法,結果一定是 float
// 7 // 2 3 整除,捨去小數
% 7 % 2 1 餘數
** 2 ** 10 1024 次方
0.1 + 0.2 不等於 0.3
0.1 + 0.2          # 0.30000000000000004
0.1 + 0.2 == 0.3   # False

電腦用二進制儲存 float,大部分小數只能儲存一個非常接近的值。計算價錢時,這點誤差通常無關痛癢;但不要用 == 比較兩個 float。工程線的練習會處理這個問題。

3字串 Strings

字串就是文字,用引號包住。單引號和雙引號都可以,本課統一用雙引號。

title = "看得見的資料"
len(title)              # 6:字串有多少個字
"價錢:" + str(120)      # '價錢:120':+ 把兩個字串接起來

要把數值放進一句文字裏,最方便的是 f-string:在引號前面加 f,把要放進去的值寫在 { } 裏。

price = 120
f"打八折後是 {price * 0.8} 元"    # '打八折後是 96.0 元'

最容易出錯的,是看起來像數字的字串:

"120" + "1"     # '1201':兩個字串接起來
120 + 1         # 121:兩個數字相加
"120" + 1       # TypeError: can only concatenate str (not "int") to str

"120" 有引號,是文字,不是數字。從表單、CSV 檔或網頁讀回來的資料,數字常常以字串的形式出現,要先轉換才能計算(見第 5 節)。

4布林值和 None Booleans and None

布林值只有兩個:True 和 False,注意首字母大寫。比較的結果就是布林值:

3 > 2                  # True
"apple" == "Apple"     # False:大小寫不同就是不同的字串
stock = 0
stock > 0              # False:沒有現貨

= 和 == 不同:= 是把值交給一個名字,== 是比較兩個值是否相等。

None 表示「沒有值」。M0 那本書的作者電郵在 JSON 裏寫作 null,讀入 Python 就變成 None。它和 0、""(空字串)都不同:0 是一個數字,"" 是一段沒有字的文字,None 是根本沒有填。

email = None
email is None      # True:檢查是否 None,用 is
None == 0          # False

5型別轉換 Converting between types

用型別的名字當作函式,就可以把值轉換成那個型別:

flowchart LR
    S["str<br/>#quot;120#quot;"] -->|"int()"| I["int<br/>120"]
    S -->|"float()"| F["float<br/>120.0"]
    I -->|"str()"| S
    F -->|"int():捨去小數"| I
    I -->|"float()"| F
    X["str<br/>#quot;12.5#quot;"] -.->|"int() 失敗"| E["ValueError"]
    classDef v fill:#ffffff,stroke:#d3d1cb,color:#37352f
    classDef err fill:#fdebec,stroke:#c4423d,color:#5d1715
    class S,I,F,X v
    class E err
圖 2 常用的型別轉換。箭頭旁邊是要用的函式;紅字是會失敗的例子。
int("120")       # 120
float("12.5")    # 12.5
str(12.5)        # '12.5'
int(12.9)        # 12:直接捨去小數,不是四捨五入
round(12.9)      # 13:要四捨五入用 round()

轉換不了的時候,Python 會報 ValueError,並在訊息裏引出那個值:

int("12.5")   →  ValueError: invalid literal for int() with base 10: '12.5'

讀錯誤訊息時,先看最後一行:錯誤的種類(ValueError),以及出事的值('12.5')。這裏的意思是:"12.5" 有小數點,不能直接變成整數,要先用 float()。

bool("False") 是 True

bool() 不會讀懂字串的意思,它只看「有沒有東西」:空的或零值是 False,例如空字串 ""、0、0.0、None(還有 M4 會講的空 list []、空 dict {});其餘都是 True,包括字串 "False" 和 "0"。從檔案讀到 "false"、"no" 這類文字,要自己比較:value == "true"。

6變數只是名字 A variable is just a name

price = 120 不是把 120 放進一個叫 price 的盒子裏,而是把 price 這個名字貼在 120 這個值上。同一個值可以貼上幾個名字;把名字改貼到別的值上,原來的值不受影響。

圖 3 名字和值。old_price = price 讓兩個名字指向同一個值;之後 price = 150 只是把 price 這張標籤移到新的值上,old_price 仍然指向 120。
圖 3 名字和值。old_price = price 讓兩個名字指向同一個值;之後 price = 150 只是把 price 這張標籤移到新的值上,old_price 仍然指向 120。
price = 120
old_price = price    # 兩個名字指向同一個 120
price = 150          # price 改指向 150
old_price            # 仍然是 120

這個「名字指向值」的看法,在 M4 處理 list 和 dict 時會變得很重要。

7容易混淆 Easily confused

這兩樣 分別
"120" 和 120 前者是字串,+ 會把它接起來;後者是數字,+ 會相加。
None、0、"" 沒有填、填了零、填了空白文字。三者互不相等。
= 和 == 前者把值交給一個名字;後者比較兩個值是否相等。
/ 和 // 前者是除法,結果一定是 float;後者是整除,捨去小數。
int(12.9) 和 round(12.9) 前者捨去小數得 12;後者四捨五入得 13。
JSON 的 true/null 和 Python 的 True/None 寫法不同,意思相同;讀入時自動轉換。

8動手:新書到貨 Hands-on: new arrivals

  1. 下載 m3-new-arrivals.ipynb 和 new-arrivals.json,放進 python-course 資料夾;
  2. 執行 uv run jupyter lab,打開 notebook,逐格執行。

小書店收到一批新書的資料,是從網上表單匯出的:有些價錢是字串,有些庫存沒有填。你要先查出每個值的型別,找出會令計算出錯的值,再把它們轉換好,算出這批書的總值。

工程線(選做)

m3-sensor-units-eng.ipynb:浮點數誤差和 math.isclose、攝氏轉換成開爾文和華氏,以及用 None 表示缺失的讀數、計算平均值時把它跳過。

下一步

M4 講容器:用 list 和 dict 把很多個值組織起來,也就是 JSON 和 YAML 讀入後的樣子。