程式語言的核心任務,主要就是數值的運算或對資料的操作。本章首先針對常用的資料、容器類型以及基本的操作方式作概觀性的介紹:
對 Python 來說,程式碼裡操作的所有東西都是物件(Object),所以比較正確的來說,我們會介紹的是 Python 裡的物件型別(Object types)。Python常用的內建物件包含了數值(Number)、序列(Sequence)、集合(Set)、對應集(Mapping)資料型別,以及檔案和None等物件。主要的資料型別裡,有的物件型別的資料內容可以就地變更(Mutable),有的不能就地變更(Immutable),常用型別的如以下表格所列。
物件類型 | Mutability | 內建物件型別 |
---|---|---|
數值 | immutable | int , bool , float , complex |
序列 | mutable | list , bytearray |
序列 | immutable | str , tuple , bytes |
對應集 | mutable | dict |
集合 | mutable | set |
檔案/串流 | n/a | file |
NoneType | n/a | None |
type()
可以用來檢驗物件的型態。型別 | 範例 |
---|---|
int | 1234 , −24 ,0 , 0x9ff (十六進位), 0b1111 (二進位) |
bool | True (1), False (0) |
float | 1.23 , 3.14e-10 , 4E210 , 4.0e+210 , 1. , .1 |
complex | 3+4j , 3.0+4.0j , 3J |
int()
、float()
、complex()
可以用來將字串轉換成數值類型。ord()
可以用來將字元轉換成對應的字碼值,是 chr()
的逆向操作。print()
可以用來將數值內容輸出至畫面。# 小小的小數點很容易被忽略,有沒有一個小點是不一樣的
type(17), type(17.), type(.17)
(int, float, float)
# 布林值是整數 int 的子類別,但不是用來作數值運算的,主要用於流程控制時的條件判斷
type(False) is bool, type(True) == bool
(True, True)
# 從字串轉換成數值
print('number1 =', int('0x41', base=16), ', number2 =', float(' 1e-003 \n'))
number1 = 65 , number2 = 0.001
# 字元 'A' 的 ASCII 碼
ord('A'), chr(0x41)
(65, 'A')
str
字串¶str
字串是以字元為元素的序列資料結構,字串的語法使用單引號或雙引號包起來,一樣的引號要成對使用。
元素內容是按照儲存順序的 index 存取,語法為 [ index ]
。 如果按照由前往後的順序,第一個元素 index 是0,依次往後遞增; 如果反過來由後往前存取,最後一個元素 index 可以用-1,依次向前遞減。
字串範例 | 說明 |
---|---|
'' |
空字串 |
"Python's" , 'Python"s' |
字串用單引號或雙引號包起來 |
'Python\'s\n' |
特殊字元前面要加反斜線 \ |
r'c:\Users\name' |
引號前置碼r 保留字串呈現的原貌(raw string) |
"This" "is" "concatenated" |
相鄰的字串會自動被串接起來 |
str()
回傳物件的字串版本。hex()
、bin()
分別可以用來將數值轉換成十六進位及二進位的數字字串。chr()
可以用來將字碼轉換成對應的字元,是 ord()
的逆向操作。len()
可以用來回傳字串的長度。print()
可以用來將字串內容輸出至畫面。# 包含特殊字元的字串
print('拍神\t' '好\n' '好玩')
拍神 好 好玩
# 相鄰的字串視為串接起來的一個字串
print('拍神' '好' '好玩'), len('拍神' '好' '好玩')
拍神好好玩
(None, 5)
# 當用於邏輯條件判斷時,空字串視為 False,其他則視為 True
bool(''), bool('any string'), bool('False')
(False, True, True)
# 輸出不同進位制的數字字串
ord('A'), hex(ord('A')), bin(ord('A'))
(65, '0x41', '0b1000001')
list
序列容器¶list
是存放序列性資料的結構。語法使用逗號 ,
分隔資料元素,用中括號(square brackets)[
]
成對包住所有元素。list
可以是巢狀多維度的,同一個list
中也可以存放異質類型資料,不過一般使用情境還是以同類型的資料較適合。
元素內容是按照儲存順序的 index 存取,語法為 [ index ]
。 如果按照由前往後的順序,第一個元素 index 是0,依次往後遞增; 如果反過來由後往前存取,最後一個元素 index 可以用-1,依次向前遞減。
List 範例 | 說明 |
---|---|
[] |
空的 list |
[5, 6, 7, 8] |
四個數字元素的 list |
['code', [42, 3.1415], 1.23, {}] |
巢狀、異質的 list |
list()
可以用來從現有物件的資料實體中生成一個新的list。len()
可以用來回傳容器裡的元素個數。min()
可以用來回傳容器中最小的元素。max()
可以用來回傳容器中最大的元素。# 利用內建函式 range(stop) 產生整數數列的 List
# range 預設從 0 開始直到指定的整數“的前一個整數”
list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 也可以分別指定開始、結束、及區間間隔 range(start, stop, step)
L = list(range(9, -10, -1))
L
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
# 用 index 存取 List 元素
L[0], L[len(L) - 1]
(9, -9)
# 搭配使用內建函式
min(L), max(L)
(-9, 9)
# 空的 List 在邏輯上是 False
bool([]), list(range(0)) == []
(False, True)
tuple
序列容器¶tuple
也是存放序列性資料的結構。語法使用逗號 ,
分隔資料元素,用小括號(parentheses)(
)
成對包住所有元素,但括號可以省略。 tuple
可以是巢狀多維度的,同一個tuple
中也可以存放異質類型資料,通常使用在函式參數的傳遞與回傳。
元素內容是按照儲存順序的 index 存取,語法為 [ index ]
。 如果按照由前往後的順序,第一個元素 index 是0,依次往後遞增; 如果反過來由後往前存取,最後一個元素 index 可以用-1,依次向前遞減。
tuple 範例 | 說明 |
---|---|
() |
空的 tuple |
('code',) |
單一元素的 tuple |
(5, 6, 7, 8) |
四個數字元素的 tuple |
('code', (42, 3.1415), 1.23, {}) |
巢狀、異質的 tuple |
'code', 42, 3.1415, 1.23 |
括號可以省略 |
tuple()
可以用來從現有物件的資料實體中生成一個新的tuple。len()
可以用來回傳容器裡的元素個數。min()
可以用來回傳容器中最小的元素。max()
可以用來回傳容器中最大的元素。# 單一元素 tuple 的表示比較特殊,逗號不能省略
tuple([99]) == (99,)
True
# 內建函式 range() 一樣可以用來幫忙產生整數數列的 tuple
t = tuple(range(1, 10, 2))
t
(1, 3, 5, 7, 9)
# 用 index 存取 tuple 元素,以及內建函式的使用
t[0], t[4], len(t), min(t), max(t)
(1, 9, 5, 1, 9)
dict
字典容器¶dict
是非序列式的資料結構,元素內容的儲存是成對的 key 和對應的 value。語法使用冒號組成 key 和 value 對應組 key:value
,以逗號 ,
分隔對應組元素,用大括號(curly braces){
}
成對包住所有元素。 同一個 dict
中的 value
可以存放異質類型資料。dict
也可以是巢狀的,也就是 value
中含有另外一個 dict
類型的資料。
元素內容必須用 key
來存取,語法為 [ key ]
。
dict 範例 | 說明 |
---|---|
{} |
空的 dict |
{'alpha': 2, 'beta': 3} |
兩個元素的 dict |
{ 'parameter': { 42: 1.5, 'angle': 30 }, 'date': ['2018-06-08'] } |
巢狀、異質的 dict |
dict([['a', 1], ['b', 2], ['c', 3]]) |
由list中建構一個新的dict物件 |
dict()
可以用來從現有物件的資料實體中生成一個新的字典容器。len()
可以用來回傳容器裡key-value對的個數。# Dict 非常適合用在非同質性資料組成的記錄集
d1 = {'name':'鮑伯', 'age':45, 'job':('經理', '研發')}
d1['name'], d1['age'] < 50
('鮑伯', True)
# 由 List 中對應元素產生
d2 = dict([[1, 'one'], [2, 'two'], [3, 'three']])
print(d2[1], d2[2], d2[3])
one two three
set
集合容器¶set
是非序列式、元素內容不重複的資料結構,提供了數學集合運算方法的支援,如聯集(union)、交集(intersection)、差集(difference)、對稱差(symmetric difference)。 可以使用大括號{
}
或set()
函式建立集合物件,集合成員以逗號,
分隔。 雖然不是序列式的容器,但是 set
物件也支援逐項元素存取的 iteration 操作。
set 範例 | 說明 |
---|---|
set() |
空的集合,注意不能用 {} |
{'apple', 'orange'} |
兩個元素的集合 |
{'orange', 'banana', 5, ('pear',20)} |
異質元素的集合 |
set(['a', 'b', 'c']) |
由 list 中建構一個新的集合物件 |
set()
可以用來從現有物件的資料實體中生成一個新的集合。len()
可以用來回傳容器裡元素成員的個數。s1 = set('abracadabra')
s2 = set('alacazam')
print('集合1: ', s1)
print('集合2: ', s2)
集合1: {'a', 'r', 'd', 'b', 'c'} 集合2: {'a', 'l', 'm', 'z', 'c'}
# 聯集:所有集合1與集合2有出現的元素
s1 | s2
{'a', 'b', 'c', 'd', 'l', 'm', 'r', 'z'}
# 交集:同時有出現在兩個集合的元素
s1 & s2
{'a', 'c'}
# 差集:只在集合1,不在集合2的元素
s1 - s2
{'b', 'd', 'r'}
# 對稱差:沒有同時出現在兩個集合的元素
s1 ^ s2
{'b', 'd', 'l', 'm', 'r', 'z'}
# 數值運算範例 - 計算一個很大的數字有幾位數
len(str(2 ** 1000))
302
這些運算子不是只有數值可以用。 這是物件導向的一個重要的特質叫*多型* : 相同概念的方法,行為會因為作用在不同類型的物件而有所改變。
# 字串支援 '+' 和 '*' 的運算
p = '拍神' + '好棒棒'
p * 3
'拍神好棒棒拍神好棒棒拍神好棒棒'
# List 與同樣是序列容器的字串一樣,支援 '+' 和 '*' 的運算
L = list(p) + [1, 2, 3]
L * 2
['拍', '神', '好', '棒', '棒', 1, 2, 3, '拍', '神', '好', '棒', '棒', 1, 2, 3]
布林的運算 | 程式解譯邏輯 | 說明 |
---|---|---|
X or Y | 假如X為False則Y,否則X。 | 其中一個為True就是True,否則是False |
X and Y | 假如X為False則X,否則Y。 | 兩個都為True才是True,否則是False |
not X | 假如X為False則True,否則False。 | 反轉 |
比較的運算 | 說明 |
---|---|
X < Y | 小於 |
X <= Y | 小於或等於 |
X > Y | 大於 |
X >= Y | 大於或等於 |
X == Y | 等於 |
X != Y | 不等於 |
X is Y | 是否相同物件 |
X is not Y | 是否不同物件 |
id()
取得。 當 is
比較兩個物件是否相同時,實際比較的就是兩個物件是否有相同 id()
。# 不同的數值型態可以互相比較(實際上是,int 2會先被自動轉型提升為 float,再進行比較)
type(2), type(2.0), 2 == 2.0
(int, float, True)
# 兩個字串用比較運算子時,方法是從第一個字元開始,比較出現第一個不同字元的 ASCII 碼(ord())的大小
s1 = 'This is a book'; s2 = 'That is a book'
'i' > 'a', s1 < s2, s1 == s2, s1 > s2
(True, False, False, True)
# 兩個 List 或兩個 Tuple 用比較運算子時,方法是從第一個元素開始,比較出現第一個不同元素的大小
L1 = [1, 2, 3, 4, 5]; L2 = [1, 2, 4]
L1 < L2, L1 == L2, L1 > L2
(True, False, False)
# 不同型別不能作比較,除了(型別1 == 型別2)永遠回傳 False 以外,其他的比較都會出現 TypeError 的錯誤
17 == '17'
False
a = 3
print(type(a))
# 改變 a 參考的物件
a = 'a string'
print(type(a))
# 再一次改變 a 參考的物件
a = [5, 6, 7]
print(type(a))
<class 'int'> <class 'str'> <class 'list'>
Python是強型別(strongly typed)的程式語言。在操作運算兩個不同型別的物件時,不相容的型別不會私下自動轉換(implicit type conversions)。程式設計員必須明確知道要的操作運算是甚麼,自己明確指定型別轉換。
如果知道字串內容是數字的格式,可以用 int(), bool(), float(), complex() 來轉型。 而幾乎所有的物件都可以使用 str() 來呈現字串版的物件內容。
a = 3
b = '8'
# 數值與字串相加結果未定義,如果沒有明確轉型,會出現 TypeError 的錯誤
a + b
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-32-456c7e2c7a20> in <module> 2 b = '8' 3 # 數值與字串相加結果未定義,如果沒有明確轉型,會出現 TypeError 的錯誤 ----> 4 a + b TypeError: unsupported operand type(s) for +: 'int' and 'str'
L = list(range(7))
# 把 List 物件內容用字串表示
str(L)
'[0, 1, 2, 3, 4, 5, 6]'
兩個變數可以共享物件的參考。當變數 a 和 b 參考至同一個物件:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = a
# "=="比較內容,"is"判斷是否為同一個物件參考,應該都會是 True
print('"b == a"', b == a)
print('"b is a"', b is a)
"b == a" True "b is a" True
# a 和 b 參考至同一物件
a = b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 修改一個的元素內容,另一個會跟著變
b[-1] = 11
print('"b == a"', b == a)
print('"b is a"', b is a)
"b == a" True "b is a" True
# a 和 b 參考至同一物件
a = b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 指定相同內容的新物件給 b,兩變數的參考物件變成不同
b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print('"b == a"', b == a)
print('"b is a"', b is a)
"b == a" True "b is a" False
# a 和 b 參考至同一物件
a = b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 同樣是指定了新物件 - list經過索引返回的片段是新的物件
b = a[:]
print('"b == a"', b == a)
print('"b is a"', b is a)
"b == a" True "b is a" False
# List 是最常用的序列容器
L = list(range(1, 10))
(L[0] == L[-len(L)]) and (L[-1] == L[len(L) - 1])
True
# 字串是字元的序列
s = str(L)
(s[1] == '1') and (s[-2] == '9') and (s[1] < s[-2])
True
由序列容器中取出片段成為一個新的序列容器物件,可以取得的片段範圍僅限於合法的索引範圍。若指定的片段超過範圍,所產生的新序列容器只會包含合法範圍內的片段,Python不會發出錯誤訊息。片段範圍的指定一樣使用中括號,語法如下:
[ 起始序號 : 結束序號 : 遞增(減)量 ]
[start : end]
取的是 [start,end) 的區間。Slicing 的操作 | 說明 |
---|---|
S[1:3] |
取元素範圍序號 1 到 2 |
S[1:] |
取元素範圍序號 1 到最後一個 |
S[:-1] |
取元素範圍第一個到最後一個的前一個 |
S[:] |
取所有範圍的元素 |
S[2::3] |
元素範圍序號 2 到最後一個,每遞增 3 個序號取 |
S[::2] |
所有元素的範圍內,從頭到尾每隔一個序號取 |
S[::-1] |
反向取所有範圍的元素 |
S[-2:0:-1] |
所有範圍的元素去頭尾,反向取 |
# List slicing 練習
L = list(range(1, 10))
L[:-1] + L[::-1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1]
# List slicing 練習
L[6:] + L[-2:0:-1]
[7, 8, 9, 8, 7, 6, 5, 4, 3, 2]
成員的操作 | 說明 |
---|---|
x in S |
S 的成員裡有 x(只要值相同就算),結果為 True 或 False |
x not in S |
S 的成員裡沒有 x ,結果為 True 或 False |
for x in S: |
(迴圈)列舉 S 裡的成員到 x |
# 判斷是否存在成員
L = list(range(10))
(9 in L) and (10 not in L)
True
當序列容器或可迭代(iterable)物件在等號(=
, assignment)右邊,等號左邊如果有對應元素個數的變數,容器的元素內容會自動分派卸載。
自動卸載 | 結果 |
---|---|
a, b, c = [1, 2, 3] |
a = 1, b = 2, c = 3 |
a, b, c = (1, 2, 3) |
a = 1, b = 2, c = 3 |
a, b, c = 1, 2, 3 |
a = 1, b = 2, c = 3 |
a, b, c = range(3) |
a = 0, b = 1, c = 2 |
容器卸載是將每個元素拆到容器外,卸載操作通常用在卸載不同類型容器的內容到新容器,或容器內容卸載為叫用函式的參數。 一般可以列舉的、序列型態的容器、字典的 key 都用 *
操作,字典容器的 value 用 **
卸載。
卸載操作 | 輸出 |
---|---|
print(*range(4)) |
0 1 2 3 |
*range(4), |
(0, 1, 2, 3) |
[*range(4), 4] |
[0, 1, 2, 3, 4] |
'unpack keys: {}, {}'.format(*{'a':1, 'c':3}) |
'unpack keys: a, c' |
'unpack values: {a}, {c}'.format(**{'a':1, 'c':3}) |
'unpack values: 1, 3' |
# 用在函式的呼叫,卸載到函式的參數
print(*[1], *[2], 3, *[4, 5])
1 2 3 4 5
# 用在將非同類型容器的內容卸載到新容器
[*range(4), 4, *(5, 6, 7)]
[0, 1, 2, 3, 4, 5, 6, 7]
# 卸載 dict 的 key
'Coordinate System: {}, {}'.format(*{'latitude': '37.24N', 'longitude': '-115.81W'})
'Coordinate System: latitude, longitude'
# 卸載 dict 的 value
'Coordinates: {latitude}, {longitude}'.format(**{'latitude': '37.24N', 'longitude': '-115.81W'})
'Coordinates: 37.24N, -115.81W'