純量類型

There are only two hard things in Computer Science: cache invalidation and naming things.

Phil Karlton

作為一個廣泛用途程式語言(general-purposed programming language),Python 基本的的資料單位是純量(scalar),這一點與許多為資料科學量身設計的程式語言(例如以**向量(vector)為基本單位的 R 語言或者以資料集(dataset)**為基本單位的 SAS)有著極為巨大的差異。我們在這個小節中介紹 Python 基本的純量類型:

  • 整數(int)
  • 浮點數(float)
  • 文字(str)
  • 布林(bool)
  • None(NoneType)

使用 type() 函數回傳純量類型

我們使用 = 符號將不同類型的資料指派給符合寫作風格(請參考起步走)的物件名稱,使用者不需要自己去猜測純量類型,而是使用一個函數 type() 讓 Python 告訴我們答案為何。

my_int = 87
my_float = 8.7
my_str = "Hello Python"
bool_true = True
bool_false = False
none_type = None

print(type(my_int))
print(type(my_float))
print(type(my_str))
print(type(bool_true))
print(type(bool_false))
print(type(none_type))
1
2
3
4
5
6
7
8
9
10
11
12
13
## <class 'int'>
## <class 'float'>
## <class 'str'>
## <class 'bool'>
## <class 'bool'>
## <class 'NoneType'>
1
2
3
4
5
6

整數與浮點數

我們使用整數與浮點數進行運算,常用的數學運算符號有七種:

  • +-*/ :加減乘除
  • ** :次方
  • % :回傳餘數
  • // :回傳商數
print(8 + 7)
print(8 - 7)
print(8 * 7)
print(8 / 7)
print(8**7)
print(87 % 7)
print(87 // 7)
1
2
3
4
5
6
7
## 15
## 1
## 56
## 1.1428571428571428
## 2097152
## 3
## 12
1
2
3
4
5
6
7

特別值得注意的是在使用除法這個運算符號時,Python 2 會將兩個整數相除結果以整數類型回傳(解決辦法很單純,更改為 8.0/78/7.08.0/7.0 即可),這點在 Python 3 中改為自動轉換為浮點數類型回傳。

數值運算中 Python 遵循常見的次方優先、先乘除後加減等慣例,因此如果在算式中希望調整優先順序,可以使用小括號 () 包括希望先完成運算的部分,我們使用 BMI(身體質量指數)計算來暸解這個慣例,計算的對象是 NBA 史上最偉大的中鋒之一「柴油引擎」俠客歐尼爾(Shaquille O’Neal)巔峰時期的身高為 216 公分、體重為 147 公斤。

shaq_height = 216
shaq_weight = 147
shaq_bmi = shaq_weight/(shaq_height/100)**2 # 將身高轉換為以公尺為單位

print(shaq_bmi)
1
2
3
4
5
## 31.507201646090532
1

文字

我們使用成雙的單引號 '' 或成對的雙引號 "" 來建立文字類型(str),多數的時候使用單引號或者雙引號不會有任何分別。

hello_wld = 'Hello world!'
hello_py = "Hello Python!"
print(hello_wld)
print(hello_py)
print(type(hello_wld))
print(type(hello_py))
1
2
3
4
5
6
## Hello world!
## Hello Python!
## <class 'str'>
## <class 'str'>
1
2
3
4

但是在部分情境中,使用成雙的單引號或成對的雙引號標註文字是有差別的,像是在英文句子中經常出現的非成雙單引號 '(apostrophe)以及用作嘲諷強調的空氣雙引號(air quotes),當文字中的內容有出現這些元件時如果沒有特別關注,宣告的當下就會產生錯誤。

# SyntaxError: invalid syntax
mcd = 'I'm lovin it'
shaq = 'Shaquille O'Neal'
ross_said = "Let's put aside the fact that you "accidentally" pick up my grandmother's ring."
1
2
3
4
##   File "<ipython-input-14-7182301d7883>", line 1
##     mcd = 'I'm lovin it'
##              ^
## SyntaxError: invalid syntax
1
2
3
4

這時候我們可以使用跳脫字元反斜線 \ 來完成宣告或者使用不同樣式的引號。

mcd = 'I\'m lovin it' # mcd <- "I'm lovin it" 
shaq = 'Shaquille O\'Neal' # shaq <- "Shaquille O'Neal"
ross_said = "Let's put aside the fact that you \"accidentally\" pick up my grandmother's ring." # ross_said <- 'Let\'s put aside the fact that you "accidentally" pick up my grandmother\'s ring.'
print(mcd)
print(shaq)
print(ross_said)
1
2
3
4
5
6
## I'm lovin it
## Shaquille O'Neal
## Let's put aside the fact that you "accidentally" pick up my grandmother's ring.
1
2
3

運用文字時常會使用到的技巧是以特定格式印出(print with format),具體來說是在文字中嵌入已經宣告好的物件,以 .format() 方法作為實踐的管道,以 {} 作文字或者以 {:f} 做數值等不同類型的嵌入。

shaq_height = 216
shaq_weight = 147
shaq_bmi = shaq_weight/(shaq_height/100)**2

print("俠客歐尼爾的 BMI 為 {}%".format(shaq_bmi))
print("俠客歐尼爾的 BMI 為 {:.2f}%".format(shaq_bmi))
1
2
3
4
5
6
## 俠客歐尼爾的 BMI 為 31.507201646090532%
## 俠客歐尼爾的 BMI 為 31.51%
1
2

Python 在文字上運算的彈性較大一些,可以利用 + 進行文字的合併(concatenation),以及利用 * 進行複製。

first_name = "Shaquille"
last_name = "O'Neal"
print(first_name + " " + last_name)
print((first_name + " " + last_name + " ") * 3)
1
2
3
4
## Shaquille O'Neal
## Shaquille O'Neal Shaquille O'Neal Shaquille O'Neal
1
2

布林

當我們進行判斷條件或者資料篩選的時候會需要仰賴布林(bool),布林只有 TrueFalse 這兩個值。

print(type(True))
print(type(False))
1
2
## <class 'bool'>
## <class 'bool'>
1
2

這裡特別提醒一個觀念,Python(或者絕大多數的程式語言)對於英文的大小寫是敏感的(case-sensitive),像是 True 會被識別為布林,但是 TRUE 或者 true 則會被視作物件名稱。

## <class 'bool'>
## <class 'bool'>
## ---------------------------------------------------------------------------
## NameError                                 Traceback (most recent call last)
## <ipython-input-3-9587d715c4c4> in <module>()
##       2 print(type(False))
##       3 # recognized as object names
## ----> 4 print(type(true))
##       5 print(type(TRUE))
##       6 print(type(false))
## 
## NameError: name 'true' is not defined
1
2
3
4
5
6
7
8
9
10
11
12

除了直接輸入布林,我們也可以透過判斷條件得到布林,常用的布林運算符號有:

  • ==!= :等於以及不等於
  • >>=<<= :大於、大於等於、小於以及小於等於
  • isis not :是否為相同的值與類型
  • andor :交集與聯集
  • not :非
  • in :是否存在於
print(8 == 7) # 判斷 8 是否等於 7
print(8 != 7) # 判斷 8 是否不等於 7
print(8 > 7) # 判斷 8 是否大於 7
print(8 >= 7) # 判斷 8 是否大於等於 7
print(8 < 7) # 判斷 8 是否小於 7
print(8 <= 7) # 判斷 8 是否小於等於 7
print(8 is 7) # 判斷 8 與 7 是否為同樣的類別或值
print(8 is not 7) # 判斷 8 與 7 是否為相異的類別或值
print(True and False) # 判斷 True 與 False 的交集
print(True or False) # 判斷 True 與 False 的聯集
print(not(8 > 7)) # 反轉 8 是否大於 7 的判斷
print("H" in "Hello world") # 判斷 H 是否存在於 Hello world 之中
1
2
3
4
5
6
7
8
9
10
11
12
## False
## True
## True
## True
## False
## False
## False
## True
## False
## True
## False
## True
1
2
3
4
5
6
7
8
9
10
11
12

在 Python 中, True 跟數值 1 相等; False 跟數值 0 相等。如果在數值運算中納入了布林不會產生任何問題。

print(True == 1)
print(False == 0)
print(1 + True)
print(1 + False)
1
2
3
4
## True
## True
## 2
## 1
1
2
3
4

有關於布林在判斷條件或者資料篩選的應用,將在後續章節中探討。

None

None 是所謂的無值,或者可以用 NA 值(Not Available)或 NaN 值(Not a Number)去體會它,None 是無回傳值函數中的預設輸出值、也是搜索特徵函數找不到情況下的預設輸出值。在範例程式中,我們宣告了一個只有 pass 保留字內容的 hello_world() 函數(有關宣告函數的相關討論,我們會在後續章節詳述),這就是一個所謂的無回傳值函數,接著檢視這個函數的輸出與輸出類型。

def hello_world():
  pass

print(hello_world())
print(type(hello_world()))
1
2
3
4
5
## None
## <class 'NoneType'>
1
2

判斷純量類型的函數

使用 isinstance(x, classinfo) 函數判斷純量類型,其中 x 輸入物件名稱、 classinfo 輸入類型名稱。

# 判斷是否為整數
print(isinstance(87, int))
print(isinstance("87", int))
# 判斷是否為浮點數
print(isinstance(87.0, float))
print(isinstance(87, float))
# 判斷是否為文字
print(isinstance("True", str))
print(isinstance(True, str))
# 判斷是否為布林
print(isinstance(False, bool))
print(isinstance("False", bool))
# 判斷是否為 None
print(isinstance(None, type(None)))
print(isinstance("None", type(None)))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## True
## False
## True
## False
## True
## False
## True
## False
## True
## False
1
2
3
4
5
6
7
8
9
10

轉換純量類型的函數

使用與目標轉換類型同名的函數轉換純量類型。

  • int():轉換純量為整數類型
  • float():轉換純量為浮點數類型
  • bool():轉換純量為布林類型
  • str():轉換純量為文字類型

使用 int() 函數可以輸入浮點數、布林與文字讓 Python 轉換成整數。

print(int(8.7))
print(int(True))
print(int(False))
print(int("87"))
1
2
3
4
## 8
## 1
## 0
## 87
1
2
3
4

使用 float() 函數可以輸入整數、布林與文字讓 Python 轉換成浮點數。

print(float(87))
print(float(True))
print(float(False))
print(float("87"))
1
2
3
4
## 87.0
## 1.0
## 0.0
## 87.0
1
2
3
4

使用 bool() 函數可以輸入整數、浮點數與文字讓 Python 轉換成布林,輸入浮點數或整數類型的 0 會轉換成為 False ,其他數字則一律轉換為 True

print(bool(0))
print(bool(0.0))
print(bool(1))
print(bool(1.0))
print(bool(8.7))
print(bool(-8.7))
1
2
3
4
5
6
## False
## False
## True
## True
## True
## True
1
2
3
4
5
6

bool() 函數中若輸入文字,無論輸入文字內容為何都一律轉換成 True

print(bool("True"))
print(bool("TRUE"))
print(bool("true"))
print(bool("False"))
print(bool("FALSE"))
print(bool("false"))
1
2
3
4
5
6
## True
## True
## True
## True
## True
## True
1
2
3
4
5
6

使用 str() 函數可以輸入整數、浮點數與布林讓 Python 轉換成文字。

print(str(87))
print(str(87.0))
print(str(True))
print(str(False))
1
2
3
4
## 87
## 87.0
## True
## False
1
2
3
4

純量轉換類型應用:以 input() 函數為例

簡單的純量轉換類型應用與 input() 函數的介紹有關,Python 內建的 input() 函數可以使用終端機提示來獲取使用者輸入,在 Jupyter Notebook 生態系中,執行到 input() 函數時儲存格會呈現忙碌的情況,一直等待使用者完成輸入,舉例來說前述計算 BMI(身體質量指數)時我們是直接將計算對象 NBA 史上最偉大的中鋒之一「柴油引擎」俠客歐尼爾(Shaquille O’Neal)巔峰時期的身高與體重宣告在程式之中;但是透過 input() 函數就可以計算任何使用者輸入的球員身高與體重與其所對應的身體質量指數。

input() 函數可以使用終端機提示來獲取使用者輸入

特別值得注意的地方是,經過 input() 函數所輸入的純量類型都會以文字類型儲存。

player_name = input("請輸入球員姓名:")
player_height = input("請輸入球員身高(cm):")
player_weight = input("請輸入球員體重(kg):")
print(type(player_name))
print(type(player_height))
print(type(player_weight))
1
2
3
4
5
6
## 請輸入球員姓名:俠客歐尼爾
## 請輸入球員身高(cm):216
## 請輸入球員體重(kg):147
## <class 'str'>
## <class 'str'>
## <class 'str'>
1
2
3
4
5
6

這個特性導致即便我們在提示對話框中輸入的是整數類型也會以文字類型賦值給物件,而文字類型是無法自由地運用所有數值運算符號的。

# TypeError: can't multiply sequence by non-int of type 'float'
player_name = input("請輸入球員姓名:")
player_height = input("請輸入球員身高(cm):")
player_weight = input("請輸入球員體重(kg):")
player_bmi = player_weight/(player_height*0.01)**2
1
2
3
4
5
## 請輸入球員姓名:俠客歐尼爾
## 請輸入球員身高(cm):216
## 請輸入球員體重(kg):147
## ---------------------------------------------------------------------------
## TypeError                                 Traceback (most recent call last)
## <ipython-input-48-fbb38502cf16> in <module>()
##       2 player_height = input("請輸入球員身高(cm):")
##       3 player_weight = input("請輸入球員體重(kg):")
## ----> 4 player_bmi = player_weight/(player_height*0.01)**2
## 
## TypeError: can't multiply sequence by non-int of type 'float'
1
2
3
4
5
6
7
8
9
10
11

因此獲取使用者輸入之後我們要做適當的類型轉換,才能順利完成身體質量指數的計算。

player_name = input("請輸入球員姓名:")
player_height = input("請輸入球員身高(cm):")
player_weight = input("請輸入球員體重(kg):")
player_height = float(player_height)
player_weight = float(player_weight)
player_bmi = player_weight/(player_height*0.01)**2
print("{}的身體質量指數為:{:.2f}".format(player_name, player_bmi))
1
2
3
4
5
6
7
## 請輸入球員姓名:俠客歐尼爾
## 請輸入球員身高(cm):216
## 請輸入球員體重(kg):147
## 俠客歐尼爾的身體質量指數為:31.51
1
2
3
4

巔峰時期的俠客歐尼爾雖然身體質量指數算出來很高,但由於指數並沒有將體脂肪率考量在內,所以並不能反映他當時的身體素質與體態,實際上他在巔峰時期擁有極高比例的肌肉,能夠在場上以驚人的速度與彈跳力主宰後 Michael Jordan 時代的 NBA,因此某個程度上來說,身體質量指數是一個頗為落後的指標,並不足以作為評斷一個人是否需要減(或增)重。

小結

在這個小節中我們簡介如何使用 type() 函數回傳純量類型、不同純量類型的特性(包含數值、文字、布林與 None)、判斷與轉換純量類型的函數與純量轉換類型應用。

延伸閱讀