"""
如果你已經裝好必要的Python套件環境的話,這份notebook可以在自己的電腦上執行。不然,可以使用Google的Colab。
若在Colab上開啟,請執行以下步驟:
1. 按右上角的【連線】,啟動雲端的Linux虛擬機器環境。
2. 執行這一格的程式碼,以安裝必要的套件。
"""
# 目前所有必要的套件在Colab上都有,這一格可以不用執行
!python --version
!pip list
# 日後若發現缺了某個套件,可以用 !pip install <套件名稱> 安裝
對 Python 來說,程式碼裡操作的所有東西都是物件(Object),所以比較正確的來說,以下介紹的是初學 Python 應該要知道的幾種常用物件型別(Object types): 數值(Number)、序列(Sequence)、對應集(Mapping)、以及檔案和None等物件。 有的物件型別的資料內容可以就地變更(Mutable),有的不能就地變更(Immutable)。
物件類型 | Mutability | 內建物件型別 |
---|---|---|
數值 | immutable | int , bool , float , complex |
序列 | mutable | list |
序列 | immutable | str , tuple |
對應集 | mutable | dict |
檔案/串流 | n/a | file |
NoneType | n/a | None |
type()
可以用來檢驗物件的型態。print()
可以用來把資料內容用文字方式顯示。型別 | 範例 |
---|---|
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 |
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()
用來建構新字串,或將物件轉成字串。len()
可以用來回傳字串的長度。字串類別本身有很多專屬的方法,以下是幾個常用的方法:
format()
用來格式化字串。count()
計算某個子字串出現幾次。find()
找出子字串出現的位置。lower()
返回全部是小寫的複本。upper()
返回全部是大寫的複本。replace()
將子字串全部替換成指定的字串。split()
將字串按照指定的分隔符號切割。strip()
移除字串前後的空白字元。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()
可以用來回傳容器中最大的元素。list
是序列容器,可以使用序列容器的共通方法(參閱官方文件 Common Sequence Operations)。 此外,list
在建立後,元素內容可以就地變更(mutable),標準函式庫另外還有提供可以就地變更的方法,請參閱官方文件 Mutable Sequence Types,以下是幾個常用的list
類別方法:
append()
追加一個元素在容器後面。extend()
追加一系列的元素在容器後面。del L[m:n]
刪除範圍內的元素,與 L[m:n] = []
相同。copy()
產生一份複製,與 L[:]
相同。clear()
移除所有的元素,與 del L[:]
相同。insert()
插入元素到某個位置。remove()
移除第一個出現的指定元素值。pop()
回傳某個位置的元素值,並從容器中移除。sort()
對元素就地排序。reverse()
就地反轉元素順序。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
在建立後,元素內容不可以就地變更(immutable)。 tuple
是序列容器,所以一般序列容器的共同方法都可以用,參閱官方文件 Common Sequence Operations。
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()
可以用來從現有物件的資料實體中生成一個新的tuple。len()
可以用來回傳容器裡key-value對的個數。dict
在建立後,元素的 value
可以就地變更(mutable),key
不可以就地變更(immutable),也不允許 mutable 的物件類型當 key
。 dict
類別常用的方法:
clear()
清除所有容器內的內容。copy()
複製。get()
回傳某個 key 的對應 value,沒有的話就回傳預設值。pop()
回傳並移除某個 key 的對應 value,沒有的話就回傳預設值。items()
回傳可迭代的所有 (key, value) view。keys()
回傳可迭代的所有 key 的 view。values()
回傳可迭代的所有 value 的 view。算數的操作 | 說明 |
---|---|
X + Y, X - Y | 加法,減法 |
**X * Y, X / Y** | 乘法,除法 |
X // Y, X % Y | 取商,取餘數 |
**X**Y** | 次方 |
布林的運算 | 程式解譯邏輯 | 說明 |
---|---|---|
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()
。Python是動態型別(dynamic type)的程式語言。為資料或物件指定變數名字時,程式碼中不需要明確宣告變數的型別。例如:當指定 a = 3
時,Python 會根據你的要求做這些步驟:
是物件擁有型別,不是變數。變數只是個指向參考物件的名字而已。
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'>
兩個變數可以共享物件的參考。當變數 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
S[3]
。0
,往後面依次遞增。如:S[0]
, S[1]
, ..., S[len(S) - 1]
。-1
,往前面依次遞減。如:S[-1]
, S[-2]
, ..., S[-len(S)]
。S[len(S)]
Python會出現錯誤訊息。由序列容器中取出片段成為一個新的序列容器物件,可以取得的片段範圍僅限於合法的索引範圍。若指定的片段超過範圍,所產生的新序列容器只會包含合法範圍內的片段,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] |
所有範圍的元素去頭尾,反向取 |
成員的操作 | 說明 |
---|---|
x in S |
S 的成員裡有 x(只要值相同就算),結果為 True 或 False |
x not in S |
S 的成員裡沒有 x ,結果為 True 或 False |
for x in S: |
(迴圈)列舉 S 裡的成員到 x |
# 用 range() 來幫忙產生整數列
L = list(range(1, 10))
print(L)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
# 取開始到倒數第二個的區間
L[:-1]
[1, 2, 3, 4, 5, 6, 7, 8]
# 反向取所有元素
L[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1]
# 兩個 list 相加結果就是做串接
L[:-1] + L[::-1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 7, 6, 5, 4, 3, 2, 1]
對於一般陳述句,Python 會一行一行往下執行,直到碰到改變流程的陳述句:
if-elif-else
: 條件陳述式,選擇性執行。while
: 條件式迴圈,迭代執行。for
: 序列式迴圈,迭代執行。條件或迴圈的語法,共同點是都在測試某個條件後,符合條件才會執行接續的區塊陳述。 Python 程式的語法中,區塊的程式碼使用 *space* 或 *tab* 縮排的層次來區隔不同執行條件的陳述句。
pass
: 佔位述句。break
: 中斷。continue
: 繼續。if-elif-else
條件陳述式由一個 if
邏輯測試條件,中間可有可無的 elif
測試條件,以及最後也是可有可無的 else
條件所組成。 每個條件都有對應的陳述式區塊,在條件測試為 True 時會被執行。 一般的形式像:
if test1:
statements1
elif test2:
statements2
else:
statements3
簡單的 if-else 指派陳述如:
if test:
x = a
else:
x = b
可以簡化成一行三元運算的陳述句:
x = a if test else b
a, b = 'good', 'bad'
# 試著改變 x = 'good', 或 x = 'bad' 看看條件測試的結果
x = 'excellent'
#x = 'good'
#x = 'bad'
if x == a:
print('x is also good')
elif x == b:
print('x is bad')
else:
print('neither good nor bad, x is {}'.format(x))
neither good nor bad, x is excellent
# 三元運算陳述句
a if x != 'bad' else b
'good'
# 一個一個字元複製直到字串完全相等
x = 'excellent'
c = ''
while c != x:
c += x[len(c)]
print(c)
excellent
# 註: Python 的空字串會被視為是其他字串的子字串
while c in x:
print(c)
if len(c) > 1:
c = c[:-1]
elif len(c) == 1:
# 試看看 c = '0' 和 c = '' 的結果有甚麼不同?
c = '0'
else:
break
print('c =', c)
excellent excellen excelle excell excel exce exc ex e c = 0
for
迴圈是一個通用的迭代器(iterator),可以用來走訪任何*序列容器的元素或可迭代(iterable)物件*。 for
迴圈區塊標頭從要走訪的 iterable_object 中循序指派內容物參考到 item,然後針對每個 item 重複執行區塊中的陳述句。
for item in iterable_object:
statements
# 變數 c 不須事先宣告,若先前已經有值也不影響 for 迴圈的執行
for c in x:
print(c)
e x c e l l e n t
for c in x:
# 試看看在 '0123456789' 字串中加入任意一個 'e', 'x', 'c', 'l', 'n', 't' 的字元,結果有甚麼不同?
if c not in '0123456789':
print(c)
else:
break
e x c e l l e n t
# 沒作甚麼事,單純占用 CPU 時間的迴圈
for i in range(2**25):
pass
跳離最近的 for
或 while
迴圈。
for i in range(10):
if i > 5: break
print(i)
0 1 2 3 4 5
在迴圈中出現時,忽略以下所有述句,回到迴圈標頭繼續下一輪迴圈。
n = list(range(10))
for i in n:
if i < 5: continue
print(i)
5 6 7 8 9
list
和 dict
容器時,Python 提供了強大的功能性語法,分別稱為 *List Comprehensions* 與 *Dict Comprehensions*。對於序列容器或可迭代物件 S 進行操作,並生成一個新的 list
物件。
成員的操作 | 說明 |
---|---|
[運算表示句 for x in S] |
針對每個 S 的成員 x 做運算,運算結果生成新的 list 物件 |
[運算表示句 for x in S if 條件] |
針對每個*符合條件*的成員 x 做運算,運算結果生成新的 list 物件 |
List comprehension 語法結構可組成相當豐富的條件式迭代運算
[運算表示句 for x1 in S1 if 條件1
for x2 in S2 if 條件2 ...
for xN in SN if 條件N]
L = [1, 2, 3, 4, 5]
# 使用 List Comprehension 生成新的 List 物件
L = [x + 10 for x in L]
print(L)
[11, 12, 13, 14, 15]
# 條件式挑選部份成員作處理
[n*2 for n in range(10) if n % 2 == 0]
[0, 4, 8, 12, 16]
對於可拆解出成對的 (key, value) 的序列容器或可迭代物件 S 進行操作,並生成一個新的 dict
物件。
成員的操作 | 說明 |
---|---|
{key:value for (key,value) in S} |
針對每個 S 的成員 x 做運算,運算結果生成新的 dict 物件 |
{key:value for (key,value) in S if 條件} |
針對每個*符合條件*的成員 x 做運算,運算結果生成新的 dict 物件 |
Dict comprehension 語法結構也可組成相當豐富的條件式迭代運算,但需注意dict
容器的 key 不能重複,若重複指定不同 value 給同一個 key,結果對應的 value 會是最後指定的值。
{key:value運算表示句 for x1 in S1 if 條件1
for x2 in S2 if 條件2 ...
for xN in SN if 條件N}
# 可迭代物件生成 dict 物件
{x: ord(x) for x in 'abc'}
{'a': 97, 'b': 98, 'c': 99}
# 條件式挑選部份成員作處理
{str(x): x ** 2 for x in range(10) if x % 2 == 0}
{'0': 0, '2': 4, '4': 16, '6': 36, '8': 64}
# 需要兩組序列進行兩兩配對的操作時,可以使用內建函式 zip() 來幫忙
{k: v for (k, v) in zip(['a', 'b', 'c'], [1, 2, 3])}
{'a': 1, 'b': 2, 'c': 3}
函式以 def
關鍵字及指定的函式名字開始,後面使用小括號接著函式運算需要的所有參數。 區塊陳述包含函式所需的運算,運算結果的值使用 return
述句返回,若未明確指定,預設返回值為 None
。
def name(arg_name1,..., arg_nameN=value):
statements
return value
可用參數定義格式 | 格式說明 |
---|---|
arg_name1 |
一般參數,以位置或名字匹配 |
arg_nameN=value |
同一般參數,明確指定預設值 |
函式呼叫
name(arg_value1,... arg_nameN=value)
可用參數定義格式 | 格式說明 |
---|---|
arg_value1 |
以位置匹配傳遞參數 |
arg_name_N=value |
以名字匹配傳遞參數 |
# 定義一個函式 Add(): 印出輸入參數相加的結果
def Add(a, b, c):
print(a + b + c)
# 函式呼叫與參數傳遞
Add(2, 3, -4)
# 以位置及名字匹配方式傳遞參數
Add(2, c=-4, b=3)
1 1
在設計程式時,建議遵循以下原則:
return
來回傳,讓呼叫端來決定是否覆蓋原物件內容。# 指派新物件不影響呼叫端
def f(a):
# 一開始 a 與呼叫端的 b 參考同一物件
print('a =', a, 'id =', id(a))
# 指派新的 int 物件
a = 9
# 現在 a 參考到新物件
print('a =', a, 'id =', id(a))
b = 5
# before function call
print('b =', b, 'id =', id(b))
f(b)
# after function called
print('b =', b, 'id =', id(b))
b = 5 id = 140708456839104 a = 5 id = 140708456839104 a = 9 id = 140708456839232 b = 5 id = 140708456839104
# 可就地變更的類別,兩邊內容是同一份
def f_list_args(L1, L2):
print('L1 =', L1, 'id =', id(L1))
# 指派新的 list 物件
L1 = list(range(7, 10))
print('L1 =', L1, 'id =', id(L1))
print('L2 =', L2, 'id =', id(L2))
# 不建議在函式中直接更改參數物件的元素內容。
L2[0] = 'changed'
print('L2 =', L2, 'id =', id(L2))
x = [2, 3]
y = [4, 5, 6]
# before function call
print('x =', x, 'id =', id(x))
print('y =', y, 'id =', id(y))
f_list_args(x, y)
# after function called
print('x =', x, 'id =', id(x))
print('y =', y, 'id =', id(y))
x = [2, 3] id = 2427060925824 y = [4, 5, 6] id = 2427061789376 L1 = [2, 3] id = 2427060925824 L1 = [7, 8, 9] id = 2427062155904 L2 = [4, 5, 6] id = 2427061789376 L2 = ['changed', 5, 6] id = 2427061789376 x = [2, 3] id = 2427060925824 y = ['changed', 5, 6] id = 2427061789376
# 有需要回傳運算結果就用 return,讓呼叫端自己決定覆蓋原物件內容。
def min_max_scaler(vec_in):
min_v = min(vec_in)
max_v = max(vec_in)
interval = max_v - min_v
vec_out = [(float(v) - min_v) / interval for v in vec_in]
return vec_out, interval
vec = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
# before function call
print('vec =', vec, 'id =', id(vec))
vec, _ = min_max_scaler(vec)
# after function called
print('vec =', vec, 'id =', id(vec))
vec = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] id = 2427061788864 vec = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] id = 2427061772544