# 1. Python 基礎
## 變數
1. 名稱必須只是一個單字。
```python
>>> # 這樣不行
>>> my variable = 'Hello'
>>> # 正確
>>> var = 'Hello'
```
2. 名稱只能包含字母 (A-z)、數字 (0-9) 與底線(`_`)字元。
```python
>>> # 這樣不行
>>> %$@variable = 'Hello'
>>> # 正確
>>> my_var = 'Hello'
>>> # 正確
>>> my_var_2 = 'Hello'
```
3. 名稱不能以數字開始。
```python
>>> # 這樣不行
>>> 23_var = 'hello'
```
4. 不要使用 Python 的關鍵字或內建函數作為變數名稱。
```python
>>> # 這樣不行
>>> if = 'hello'
>>> # 這樣也不好
>>> print = 'world'
```
## 資料型別
| 資料型別 | 範例 |
| ---------------------- | ----------------------------------------- |
| 布林值 (Bool) | `True`, `False` |
| 整數 (Integers) | `-2, -1, 0, 1, 2, 3, 4, 5` |
| 浮點數 (Floating-point numbers) | `-1.25, -1.0, -0.5, 0.0, 0.5, 1.0, 1.25` |
| 複數 (Complex numbers) | `2+1j`, `3-5j` |
| 字串 (Strings) | `'a', 'aa', 'aaa', 'Hello!', '11 cats'` |
:::info
:bulb: 可使用內建函數 `type()` 來驗證賦值給變數的值的資料型別。
:::
## 數學運算子
從**最高**到**最低**優先權:
| 運算子 | 運算 | 範例 |
| ------------ | ------------------------ | ------------------- |
| **\*\*** | 指數運算 | `2 ** 3 = 8` |
| **%** | 取餘數/模運算 | `22 % 8 = 6` |
| **//** | 向下取整除法(整數除法) | `22 // 8 = 2` |
| **/** | 浮點數除法(真除法) | `22 / 8 = 2.75` |
| **\*** | 乘法 | `3 * 3 = 9` |
| **-** | 減法 | `5 - 2 = 3` |
| **+** | 加法 | `2 + 2 = 4` |
| **>>, <<** | 位移運算 | `16 >> 2` |
| **&, ^, \|**| 位元邏輯運算 | `1 ^ 0` |
| **>, >=, ==**| 比較運算符 | `2 != 3` |
| **not, and, or** | 邏輯運算子 | `(4 < 5) and (5 < 6)`|
| **=, +=, \*=** | 指派運算子 | `a += 1` |
:::info
:bulb: 你可以使用括號來正確指定複雜運算式中運算的順序。
:::
### 運算式範例
```python
>>> 2 + 3 * 6
# 20
>>> (2 + 3) * 6
# 30
>>> 2 ** 8
# 256
>>> 10 / 2
# 5.0
>>> -11 / 2
# -5.5
>>> 23 // 7
# 3
>>> -5.0 // 2
# -3.0
>>> 23 % 7
# 2
>>> (5 - 1) * ((7 + 1) / (3 - 1))
# 16.0
```
## 增強指派運算子
| 運算子 | 等價表達 |
| ------------ | ---------------------- |
| `var += 1` | `var = var + 1` |
| `var -= 1` | `var = var - 1` |
| `var *= 1` | `var = var * 1` |
| `var /= 1` | `var = var / 1` |
| `var %= 1` | `var = var % 1` |
| `var **= 2` | `var = var ** 2` |
範例:
```python
>>> greeting = 'Hello'
>>> greeting += ' world!'
>>> greeting
# 'Hello world!'
>>> number = 1
>>> number += 1
>>> number
# 2
```
## 多重指派
```python
my_string = 'characters'
my_Boolean = True # True/False
my_integer = 5
my_floating_point = 26.2
my_complex = 2+1j # 注意:1 不能省略
# 上述程式碼等價於:
my_string, my_Boolean, my_integer, my_floating_point, my_complex = 'characters', True, 5, 26.2, 2+1j
```
## 字串串接與複製
### 字串串接
```python
>>> 'Alice' + 'Bob'
# 'AliceBob'
```
### 字串複製
```python
>>> 'Alice' * 5
# 'AliceAliceAliceAliceAlice'
```
## 註解
### 行內註解
```python
# 這是一則註解
```
### 多行註解
```python
# 這是
# 一則多行註解
```
帶有註解的程式碼:
```python
a = 1 # 初始化
```
也可以使用函數的文件字串(docstring)或多行字串作為註解:
```python
"""
這是一個函數的文件字串
你也可以把它用作多行註解
"""
```
## `print()` 函數
`print()` 函數會寫出它所給予參數的值。它能處理多個參數、浮點數以及字串。字串在印出時不會包含引號,而且各項之間會自動加入空格,這樣可以使格式看起來更整齊:
```python
>>> print('Hello world!')
# Hello world!
>>> a = 1
>>> print('Hello world!', a)
# Hello world! 1
>>> print('Hello,\
World') # 可使用反斜線 `\` 將敘述跨行
# Hello, World
```
### 跳脫序列
```python
>>> print("Welcome\nto\nthe course")
# Welcome
# to
# the course
```
### end 參數
關鍵字參數 `end` 可用來避免印出後自動換行,或以其他字串結尾:
```python
print("Welcome", end='-')
print("to the course")
...
# Welcome-to the course
```
### sep 參數
關鍵字 `sep` 用來指定多個物件之間的分隔符號,預設為空白:
```python
print('cats', 'dogs', 'mice', sep=',')
# cats,dogs,mice
```
## `input()` 函數
此函數從使用者那裡取得輸入,並將其轉換成字串:
```python
>>> print('What is your name?') # 詢問使用者的名字
>>> my_name = input()
>>> print('Hi ' + my_name)
# What is your name?
# Martha
# Hi Martha
```
`input()` 也可以直接設置預設提示訊息而不需另外使用 `print()`:
```python
>>> my_name = input('What is your name? ') # 預設提示訊息
>>> print('Hi ' + my_name)
# What is your name? Martha
# Hi Martha
```
## `len()` 函數
計算字串、清單、字典等中字符的數量,並返回其整數值:
```python
>>> len('hello')
# 5
```
## `bool()`、`int()`、`float()`、`complex()` 與 `str()` 函數
這些函數允許你轉換變數的型別。例如,你可以將 `integer` 或 `float` 轉換成 `string`:
```python
>>> str(29)
# '29'
>>> str(-3.14)
# '-3.14'
```
或者將 `string` 轉換成 `integer` 或 `float`:
```python
>>> int('11')
# 11
>>> float('3.14')
# 3.14
```
# 2. 流程控制
## 比較運算子
| 運算子 | 意義 |
|----------|-------------------------|
| `==` | 等於 |
| `!=` | 不等於 |
| `<` | 小於 |
| `>` | 大於 |
| `<=` | 小於或等於 |
| `>=` | 大於或等於 |
這些運算子會根據你給予的值計算為 `True` 或 `False`。
範例:
```python
>>> 42 == 42
True
>>> 40 == 42
False
>>> 'hello' == 'hello'
True
>>> 'hello' == 'Hello'
False
>>> 'dog' != 'cat'
True
>>> 42 == 42.0
True
>>> 42 == '42'
False
```
## 布林(邏輯)運算子
有三個布林運算子:`and`、`or` 和 `not`。
### `and` 運算子的真值表:
| 運算式 | 運算結果 |
|----------------------|-----------|
| `True and True` | `True` |
| `True and False` | `False` |
| `False and True` | `False` |
| `False and False` | `False` |
### `or` 運算子的真值表:
| 運算式 | 運算結果 |
|---------------------|-----------|
| `True or True` | `True` |
| `True or False` | `True` |
| `False or True` | `True` |
| `False or False` | `False` |
### `not` 運算子的真值表:
| 運算式 | 運算結果 |
|-------------|-----------|
| `not True` | `False` |
| `not False` | `True` |
## 混合運算子
你可以混合使用布林運算子和比較運算子:
```python
>>> (4 < 5) and (5 < 6)
True
>>> (4 < 5) and (9 < 6)
False
>>> (1 == 2) or (2 == 2)
True
```
另外,你也可以在一個運算式中同時使用多個布林運算子以及比較運算子:
```python
>>> 2 + 2 == 4 and not 2 + 2 == 5 and 2 * 2 == 2 + 2
True
```
## `if` 敘述
`if` 敘述會執行一個運算式,如果該運算式為 `True`,則執行以下縮排的程式碼:
```python
>>> name = 'Debora'
>>> if name == 'Debora':
... print('Hi, Debora')
...
# Hi, Debora
>>> if name != 'George':
... print('You are not George')
...
# You are not George
```
`else` 敘述僅在 `if` 以及所有 `elif` 運算式計算為 `False` 時執行:
```python
>>> name = 'Debora'
>>> if name == 'George':
... print('Hi, George.')
... else:
... print('You are not George')
...
# You are not George
```
只有當 `if` 敘述的運算式計算為 `False` 時,`elif` 敘述才會被計算並執行:
```python
>>> name = 'George'
>>> if name == 'Debora':
... print('Hi Debora!')
... elif name == 'George':
... print('Hi George!')
...
# Hi George!
```
`elif` 與 `else` 部分都是可選的。
```python
>>> name = 'Antony'
>>> if name == 'Debora':
... print('Hi Debora!')
... elif name == 'George':
... print('Hi George!')
... else:
... print('Who are you?')
...
# Who are you?
```
:::info
:bulb: 請注意,Python 在 Python 3.10 中引入了 [`match`](https://learnpython.com/blog/python-match-case-statement/) 敘述,作為實作 `switch` 敘述的另一種控制敘述。
:::
## `while` 迴圈敘述
`while` 迴圈用於在一個運算式為 `True` 的情況下重複執行程式碼:
```python
>>> spam = 0
>>> while spam < 5:
... print('Hello, world.')
... spam = spam + 1
...
# Hello, world.
# Hello, world.
# Hello, world.
# Hello, world.
# Hello, world.
```
## `break` 敘述
如果執行流程到達一個 `break` 敘述,它會立即退出 `while` 迴圈的區塊:
```python
>>> while True:
... name = input('Please type your name: ')
... if name == 'your name':
... break
...
>>> print('Thank you!')
# Please type your name: your name
# Thank you!
```
它同樣適用於 `for` 迴圈:
```python
>>> for i in range(5):
... if i == 3:
... break
... print(i)
# 0
# 1
# 2
```
## `continue` 敘述
當程式執行到 `continue` 敘述時,會立即跳回迴圈起始處開始下一次迭代。
```python
>>> while True:
... name = input('Who are you? ')
... if name != 'Joe':
... continue
... password = input('Password? (It is a fish.): ')
... if password == 'swordfish':
... break
...
>>> print('Access granted.')
# Who are you? Charles
# Who are you? Debora
# Who are you? Joe
# Password? (It is a fish.): swordfish
# Access granted.
```
它也適用於 `for` 迴圈:
```python
>>> for i in range(5):
... if i == 3:
... continue
... print(i)
# 0
# 1
# 2
# 4
```
## `for` 迴圈
`for` 迴圈會遍歷一個可迭代的物件,如 `range()`、`list`、`tuple`、`dictionary`、`set` 或 `string`:
```python
>>> pets = ['Bella', 'Milo', 'Loki']
>>> for pet in pets:
... print(pet)
...
# Bella
# Milo
# Loki
```
## `range()` 函數
`range()` 函數會返回一個數字序列。它從 0 開始,每次遞增 1,並在指定的數字之前停止:
```python
>>> for i in range(5):
... print('Will stop at 5! or 4 ?' + str(i))
...
# Will stop at 5! or 4 ?0
# Will stop at 5! or 4 ?1
# Will stop at 5! or 4 ?2
# Will stop at 5! or 4 ?3
# Will stop at 5! or 4 ?4
```
`range()` 函數也可以修改它的預設三個引數。前兩個分別為 `start` 和 `stop` 值,第三個為 `step` 引數。間隔值表示每次迭代後變數增加的數量。
```python
# range(start, stop, step)
>>> for i in range(0, 10, 2):
... print(i)
...
# 0
# 2
# 4
# 6
# 8
```
你甚至可以使用負數作為間隔引數,使 `for` 迴圈遞減而非遞增:
```python
>>> for i in range(5, -1, -1):
... print(i)
...
# 5
# 4
# 3
# 2
# 1
# 0
```
## 使用 `sys.exit()` 結束程式
`exit()` 函式允許結束 Python 程式。
```python
>>> import sys
>>> while True:
... feedback = input('Type exit to exit: ')
... if feedback == 'exit':
... print('You typed ' + feedback)
... sys.exit()
...
# Type exit to exit: open
# Type exit to exit: close
# Type exit to exit: exit
# You typed exit
```
## [random](https://docs.python.org/3/library/random.html) 模組
### `seed()`
`seed` 方法用於初始化隨機數產生器。
```python
>>> random.seed(1)
>>> random.random()
# 0.13436424411240122
```
設定種子為一個數字,將永遠返回相同的隨機數:
```python
>>> random.seed(1)
>>> random.random()
# 0.13436424411240122
>>> random.seed(1)
>>> random.random()
# 0.13436424411240122
>>> random.seed(1)
>>> random.random()
# 0.13436424411240122
>>> random.seed(1)
>>> random.random()
# 0.13436424411240122
>>> random.seed(1)
>>> random.random()
# 0.13436424411240122
```
### `randint()`
```python
random.randint(start: int, stop: int)
```
此方法返回介於給定起始與終止引數之間的隨機數:
```python
>>> random.randint(1, 5)
# 3
>>> random.randint(1, 5)
# 2
>>> random.randint(1, 5)
# 5
>>> random.randint(1, 5)
# 1
>>> random.randint(1, 5)
# 3
>>> random.randint(1, 5)
# 1
```
# 3. Python 函數
## 函數參數
函數可以接受 `參數` 並回傳 `返回值`:
在以下範例中,函數 `say_hello()` 接受參數 "name" 並印出問候語:
```python
>>> def say_hello(name):
... print('Hello', name)
...
>>> say_hello('Carlos')
# Hello Carlos
>>> say_hello('Wanda')
# Hello Wanda
>>> say_hello('Rose')
# Hello Rose
```
上述的函數並不回傳任何值(隱式地,回傳 `None`),這樣的函數稱為 **無返回值函數 (void function)**。以下這個函數則會回傳值,因此被稱為 **有返回值的函數 (fruitful function)**:
```python
>>> def my_sum(x,y):
... "Compute x + y."
... return x + y
>>> my_sum(1,2)
# 3
```
## 關鍵字參數 (Keyword Arguments)
在定義函數時,我們列出輸入的參數。這些參數被稱為位置參數(或位置引數),因為在 `def` 聲明中,參數的位置決定了每個參數的對應關係。
```python
>>> def poly(x,y):
... "Compute x + y**2."
... return x + y**2
>>> poly(1,2)
# 5
>>> poly(2,1)
# 3
```
我們可以為參數設定默認值:
```python
>>> def psum(x,y,p=2):
... return x**p + y**p
>>> psum(1,2)
# 5
```
為了提高程式碼可讀性,應該盡量做到明確。我們可以使用 `關鍵字參數 (Keyword Arguments)` 來實現這一點:
```python
>>> def say_hi(name, greeting):
... print(greeting, name)
...
>>> # 使用位置參數
>>> say_hi('John', 'Hello')
# Hello John
>>> # 使用關鍵字參數
>>> say_hi(name='Anna', greeting='Hi')
# Hi Anna
```
## 返回值 (Return Values)
當使用 `def` 來創建函數時,你可以使用 `return` 來指定函數的返回值。`return` 語句由以下部分構成:
- `return` 關鍵字。
- 函數應該回傳的值或表達式。
```python
>>> def sum_two_numbers(number_1, number_2):
... return number_1 + number_2
...
>>> result = sum_two_numbers(7, 8)
>>> print(result)
# 15
```
:::info
:bulb: 你經常會看到 `**kwargs` 用來收集不特定的關鍵字參數。`**kwargs` 必須是最右邊的參數。
:::
## 局部範圍與全局範圍
- 全局範圍中的程式碼不能使用任何局部變數。
- 然而,局部範圍可以訪問全局變數。
- 函數的局部範圍中的程式碼不能使用其他局部範圍中的變數。
- 如果變數位於不同範圍中,可以使用相同的名稱。也就是說,`spam` 可以是局部變數,也可以是全局變數。
```python
global_variable = 'I am available everywhere'
>>> def some_function():
... print(global_variable) # 因為是全局的
... local_variable = "only available within this function"
... print(local_variable)
...
>>> # 以下代碼會報錯,因為 'local_variable' 只存在於 'some_function' 內
>>> print(local_variable)
Traceback (most recent call last):
File "<stdin>", line 10, in <module>
NameError: name 'local_variable' is not defined
```
## `global` 語句
如果需要從函數內部修改全局變數,可以使用 `global` 語句:
```python
>>> def spam():
... global eggs
... eggs = 'spam'
...
>>> eggs = 'global'
>>> spam()
>>> print(eggs)
```
判斷變數是局部變數還是全局變數的四條規則:
1. 如果變數在全局範圍內(即在所有函數外部使用),則它總是全局變數。
2. 如果函數內有 `global` 語句對變數進行操作,那麼這個變數是全局變數。
3. 否則,如果變數在函數內的賦值語句中使用,那麼這個變數是局部變數。
4. 但是,如果變數在函數內未使用賦值語句,那麼它是全局變數。
## 導入模組
要開始導入函數,首先需要創建一個模組。**模組是一個以 `.py` 結尾的文件,包含你希望導入到程式中的程式碼**。讓我們考慮一個包含函數 `make_pizza()` 的模組。
### 直接導入
```python
import pizza
pizza.make_pizza(16, '義式臘腸')
pizza.make_pizza(12, '蘑菇')
```
### 使用 `from` 導入特定函數
```python
from pizza import make_pizza
make_pizza(16, '義式臘腸')
make_pizza(12, '蘑菇')
```
### 使用 `as` 為函數或模組取別名
```
from pizza import make_pizza as mp
mp(16, '義式臘腸')
mp(12, '蘑菇')
```
### 導入模組中的所有函數
```python
from pizza import *
make_pizza(16, '義式臘腸')
make_pizza(12, '蘑菇')
```
:::info
:bulb: 然而,在處理你沒有編寫的大型模組時,最好避免使用這種方法:如果模組中有一個函數名稱與你項目中的現有名稱相同,可能會產生意外的結果!
:::
# 4. 串列
## 使用索引獲取值
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> furniture[0]
# 'table'
>>> furniture[1]
# 'chair'
>>> furniture[2]
# 'rack'
>>> furniture[3]
# 'shelf'
```
## 負數索引
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> furniture[-1]
# 'shelf'
>>> furniture[-3]
# 'chair'
>>> f'The {furniture[-1]} is bigger than the {furniture[-3]}'
# 'The shelf is bigger than the chair'
```
## 使用切片獲取子串列
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> furniture[0:4]
# ['table', 'chair', 'rack', 'shelf']
>>> furniture[1:3]
# ['chair', 'rack']
>>> furniture[0:-1]
# ['table', 'chair', 'rack']
>>> furniture[:2]
# ['table', 'chair']
>>> furniture[1:]
# ['chair', 'rack', 'shelf']
>>> furniture[:]
# ['table', 'chair', 'rack', 'shelf']
```
切片完整串列會執行複製:
```python
>>> spam2 = spam[:]
# ['cat', 'bat', 'rat', 'elephant']
>>> spam.append('dog')
>>> spam
# ['cat', 'bat', 'rat', 'elephant', 'dog']
>>> spam2
# ['cat', 'bat', 'rat', 'elephant']
```
## 使用 `len()` 獲取串列長度
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> len(furniture)
# 4
```
## 使用索引修改值
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> furniture[0] = 'desk'
>>> furniture
# ['desk', 'chair', 'rack', 'shelf']
>>> furniture[2] = furniture[1]
>>> furniture
# ['desk', 'chair', 'chair', 'shelf']
>>> furniture[-1] = 'bed'
>>> furniture
# ['desk', 'chair', 'chair', 'bed']
```
## 串接與複製
```python
>>> [1, 2, 3] + ['A', 'B', 'C']
# [1, 2, 3, 'A', 'B', 'C']
>>> ['X', 'Y', 'Z'] * 3
# ['X', 'Y', 'Z', 'X', 'Y', 'Z', 'X', 'Y', 'Z']
>>> my_list = [1, 2, 3]
>>> my_list = my_list + ['A', 'B', 'C']
>>> my_list
# [1, 2, 3, 'A', 'B', 'C']
```
## 使用 for 迴圈與串列
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> for item in furniture:
... print(item)
# table
# chair
# rack
# shelf
```
## 使用 `enumerate()` 獲取索引
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> for index, item in enumerate(furniture):
... print('index', index, '- item:', item)
# index: 0 - item: table
# index: 1 - item: chair
# index: 2 - item: rack
# index: 3 - item: shelf
```
## `in` 與 `not in` 運算子
```python
>>> 'rack' in ['table', 'chair', 'rack', 'shelf']
# True
>>> 'bed' in ['table', 'chair', 'rack', 'shelf']
# False
>>> 'bed' not in furniture
# True
>>> 'rack' not in furniture
# False
```
## 多重賦值(拆解技巧)
多重賦值技巧是一個快捷方式,讓你能夠在一行程式碼中將多個變數賦予串列中的值。這樣,比起以下方式:
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> table = furniture[0]
>>> chair = furniture[1]
>>> rack = furniture[2]
>>> shelf = furniture[3]
```
你可以寫成這樣:
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> table, chair, rack, shelf = furniture
>>> table
# 'table'
>>> chair
# 'chair'
>>> rack
# 'rack'
>>> shelf
# 'shelf'
```
多重賦值技巧也可以用來交換兩個變數的值:
```python
>>> a, b = 'table', 'chair'
>>> a, b = b, a
>>> print(a)
# chair
>>> print(b)
# table
```
## 添加值
### `append()`
`append` 會將一個元素添加到串列的尾端:
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> furniture.append('bed')
>>> furniture
# ['table', 'chair', 'rack', 'shelf', 'bed']
```
### `insert()`
`insert` 會在指定的位置插入一個元素:
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> furniture.insert(1, 'bed')
>>> furniture
# ['table', 'bed', 'chair', 'rack', 'shelf']
```
## 刪除值
### `del`
`del` 使用索引刪除項目:
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> del furniture[2]
>>> furniture
# ['table', 'chair', 'shelf']
>>> del furniture[2]
>>> furniture
# ['table', 'chair']
```
## 使用 `sort()` 排序值
```python
>>> numbers = [2, 5, 3.14, 1, -7]
>>> numbers.sort()
>>> numbers
# [-7, 1, 2, 3.14, 5]
furniture = ['table', 'chair', 'rack', 'shelf']
furniture.sort()
furniture
# ['chair', 'rack', 'shelf', 'table']
```
你也可以為 `reverse` 參數傳入 `True` 來讓 `sort()` 反向排序值:
```python
>>> furniture.sort(reverse=True)
>>> furniture
# ['table', 'shelf', 'rack', 'chair']
```
你也可以使用內建函數 `sorted` 返回一個新的串列:
```python
>>> furniture = ['table', 'chair', 'rack', 'shelf']
>>> sorted(furniture)
# ['chair', 'rack', 'shelf', 'table']
```
## 生成式(類似於[集合建構法](https://en.wikipedia.org/wiki/Set-builder_notation))
串列生成式是一種特殊語法,讓我們可以從其他串列創建串列,當處理數字和有一層或兩層巢狀 `for` 迴圈時非常有用。
這是我們如何從現有的集合創建新串列,使用 `for` 迴圈:
```python
>>> names = ['Charles', 'Susan', 'Patrick', 'George']
>>> new_list = []
>>> for n in names:
... new_list.append(n)
...
>>> new_list
# ['Charles', 'Susan', 'Patrick', 'George']
```
這是使用串列生成式實現的相同功能:
```python
>>> names =
['Charles', 'Susan', 'Patrick', 'George']
>>> new_list = [n for n in names]
>>> new_list
# ['Charles', 'Susan', 'Patrick', 'George']
```
我們也可以對數字做相同的操作:
```python
>>> n = [(a, b) for a in range(1, 3) for b in range(1, 3)]
>>> n
# [(1, 1), (1, 2), (2, 1), (2, 2)]
```
### 添加條件
如果我們希望 `new_list` 只包含以 C 開頭的名稱,使用 `for` 迴圈,我們會這樣做:
```python
>>> names = ['Charles', 'Susan', 'Patrick', 'George', 'Carol']
>>> new_list = []
>>> for n in names:
... if n.startswith('C'):
... new_list.append(n)
...
>>> print(new_list)
# ['Charles', 'Carol']
```
在串列生成式中,我們將 `if` 語句放在結尾:
```python
>>> new_list = [n for n in names if n.startswith('C')]
>>> print(new_list)
# ['Charles', 'Carol']
```
使用 `if-else` 語句的串列推導式:
```python
>>> nums = [1, 2, 3, 4, 5, 6]
>>> new_list = [num*2 if num % 2 == 0 else num for num in nums]
>>> print(new_list)
# [1, 4, 3, 8, 5, 12]
```
:::info
:bulb: 注意,大多數情況下方法會原地修改 `list`,而函數會創建一個新的 `list`
:::
# 5. 元組
## 元組資料型別
:::info
:bulb: 元組和串列的主要區別在於,雖然 <code>元組</code> 是 <i>不可變的</i> 物件,<code>串列</code> 是 <i>可變的</i>。這意味著元組不能改變,而串列可以修改。元組比串列更節省記憶體。
:::
```python
>>> furniture = ('table', 'chair', 'rack', 'shelf')
>>> furniture[0]
# 'table'
>>> furniture[1:3]
# ('chair', 'rack')
>>> len(furniture)
# 4
```
元組與串列的主要區別是,像字串一樣,元組是不可變的。
## 在 `list()` 與 `tuple()` 之間轉換
```python
>>> tuple(['cat', 'dog', 5])
# ('cat', 'dog', 5)
>>> list(('cat', 'dog', 5))
# ['cat', 'dog', 5]
>>> list('hello')
# ['h', 'e', 'l', 'l', 'o']
```
# 6. 字串
## 字串的索引與切片
H e l l o w o r l d !
0 1 2 3 4 5 6 7 8 9 10 11
### 索引
```python
>>> spam = 'Hello world!'
>>> spam[0]
# 'H'
>>> spam[4]
# 'o'
>>> spam[-1]
# '!'
```
### 切片
```python
>>> spam = 'Hello world!'
>>> spam[0:5]
# 'Hello'
>>> spam[:5]
# 'Hello'
>>> spam[6:]
# 'world!'
>>> spam[6:-1]
# 'world'
>>> spam[:-1]
# 'Hello world'
>>> spam[::-1]
# '!dlrow olleH'
>>> fizz = spam[0:5]
>>> fizz
# 'Hello'
```
### `in` 與 `not in` 運算子
```python
>>> 'Hello' in 'Hello World'
# True
>>> 'Hello' in 'Hello'
# True
>>> 'HELLO' in 'Hello World'
# False
>>> '' in 'spam'
# True
>>> 'cats' not in 'cats and dogs'
# False
```
## 跳脫字元
跳脫字元是透過輸入反斜線 `\` 後跟隨你想要插入的字元來創建的。
| 跳脫字元 | 顯示為 |
| -------- | ----------------- |
| `\'` | 單引號 |
| `\"` | 雙引號 |
| `\t` | 水平製表符 (Tab) |
| `\n` | 換行 (換行符) |
| `\\` | 反斜線 |
```python
>>> print("Hello there!\nHow are you?\nI\'m doing fine.")
# Hello there!
# How are you?
# I'm doing fine.
```
### 原始字串
原始字串完全忽略所有跳脫字元,並將字串中出現的任何反斜線視為字面上的字元。
```python
>>> print(r"Hello there!\nHow are you?\nI\'m doing fine.")
# Hello there!\nHow are you?\nI\'m doing fine.
```
## `%` 運算元
```python
>>> name = 'Pete'
>>> 'Hello %s' % name
# "Hello Pete"
```
我們可以使用 `%d` 格式規範符將整數值轉換為字串:
```python
>>> num = 5
>>> 'I have %d apples' % num
# "I have 5 apples"
```
### 格式化字串或 f-字串
如果你使用的是 Python 3.6 或更新版本,字串 `f-字串` 是推薦的字串格式化方法。
<base-disclaimer>
<base-disclaimer-title>
來自 <a href="https://docs.python.org/3/reference/lexical_analysis.html#f-strings">Python 3 文件</a>
</base-disclaimer-title>
<base-disclaimer-content>
格式化字串字面量或 f-字串是以 `f` 或 `F` 為前綴的字串文字。這些字串可以包含替換欄位,它們是用大括號 `{}` 括起來的表達式。與其他字串字面量總是具有常數值不同,格式化字串實際上是運行時評估的表達式。
</base-disclaimer-content>
</base-disclaimer>
```python
>>> name = 'Elizabeth'
>>> f'Hello {name}!'
# 'Hello Elizabeth!'
```
甚至可以進行內聯運算:
```python
>>> a = 5
>>> b = 10
>>> f'Five plus ten is {a + b} and not {2 * (a + b)}.'
# 'Five plus ten is 15 and not 30.'
```
### 多行 f-字串
```python
>>> name = 'Robert'
>>> messages = 12
>>> (
... f'Hi, {name}. '
... f'You have {messages} unread messages'
... )
# 'Hi, Robert. You have 12 unread messages'
```
### 數字格式化
四捨五入
```python
>>> a = 3.1415926
>>> f"{a:.2f}"
# '3.14'
```
顯示為百分比
```python
>>> a = 0.816562
>>> f"{a:.2%}"
# '81.66%'
```
#### 數字格式化整理
| 數字 | 格式 | 輸出 | 描述 |
| ---------- | ------ | -------- | -------------------------------------------- |
| 3.1415926 | {:.2f} | 3.14 | 格式化浮點數為兩位小數 |
| 3.1415926 | {:+.2f}| +3.14 | 格式化浮點數為兩位小數並顯示正負號 |
| -1 | {:+.2f}| -1.00 | 格式化浮點數為兩位小數並顯示正負號 |
| 2.71828 | {:.0f} | 3 | 格式化浮點數為不顯示小數 |
| 4 | {:0>2d}| 04 | 用零填充數字(左側填充,寬度 2) |
| 11 | {:11d} | 11 | 右對齊(預設,寬度 10) |
| 11 | {:<11d}| 11 | 左對齊(寬度 10) |
| 11 | {:^11d}| 11 | 置中對齊(寬度 10) |
# 7. 字典
## 使用索引運算子 `[]` 設定鍵值
```python
>>> my_cat = {
... 'size': 'fat',
... 'color': 'gray',
... 'disposition': 'loud',
... }
>>> my_cat['age_years'] = 2
>>> print(my_cat)
...
# {'size': 'fat', 'color': 'gray', 'disposition': 'loud', 'age_years': 2}
```
## 使用索引運算子 `[]` 取得值
若字典中不存在該鍵,則會引發 <a target="_blank" href="https://docs.python.org/3/library/exceptions.html#KeyError">`KeyError`</a> 異常。
```python
>>> my_cat = {
... 'size': 'fat',
... 'color': 'gray',
... 'disposition': 'loud',
... }
>>> print(my_cat['size'])
...
# fat
>>> print(my_cat['eye_color'])
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# KeyError: 'eye_color'
```
## `values()`
`values()` 方法可取得字典中的 **值**:
```python
>>> pet = {'color': 'red', 'age': 42}
>>> for value in pet.values():
... print(value)
...
# red
# 42
```
## `keys()`
`keys()` 方法可取得字典中的 **鍵**:
```python
>>> pet = {'color': 'red', 'age': 42}
>>> for key in pet.keys():
... print(key)
...
# color
# age
```
由於預設情況下會遍歷鍵,因此無需使用 **.keys()**:
```python
>>> pet = {'color': 'red', 'age': 42}
>>> for key in pet:
... print(key)
...
# color
# age
```
## `items()`
`items()` 方法可取得字典中的 **項目**,並以一個 <router-link to=/cheatsheet/lists-and-tuples#the-tuple-data-type>元組</router-link> 的形式返回:
```python
>>> pet = {'color': 'red', 'age': 42}
>>> for item in pet.items():
... print(item)
...
# ('color', 'red')
# ('age', 42)
```
利用 `keys()`、`values()` 和 `items()` 方法,for 迴圈可以分別遍歷字典的鍵、值或鍵值對:
```python
>>> pet = {'color': 'red', 'age': 42}
>>> for key, value in pet.items():
... print(f'Key: {key} Value: {value}')
...
# Key: color Value: red
# Key: age Value: 42
```
## `get()`
`get()` 方法會返回具有指定鍵的項目的值;若該鍵不存在,則返回 `None`:
```python
>>> wife = {'name': 'Rose', 'age': 33}
>>> f'My wife name is {wife.get("name")}'
# 'My wife name is Rose'
>>> f'She is {wife.get("age")} years old.'
# 'She is 33 years old.'
>>> f'She is deeply in love with {wife.get("husband")}'
# 'She is deeply in love with None'
```
您也可以將預設的 `None` 值改成您想要的其他值:
```python
>>> wife = {'name': 'Rose', 'age': 33}
>>> f'She is deeply in love with {wife.get("husband", "lover")}'
# 'She is deeply in love with lover'
```
## 使用 `setdefault()` 新增項目
可以使用以下方式向字典中新增一個項目:
```python
>>> wife = {'name': 'Rose', 'age': 33}
>>> if 'has_hair' not in wife:
... wife['has_hair'] = True
```
使用 `setdefault` 方法,可以使程式碼更簡潔:
```python
>>> wife = {'name': 'Rose', 'age': 33}
>>> wife.setdefault('has_hair', True)
>>> wife
# {'name': 'Rose', 'age': 33, 'has_hair': True}
```
## 刪除項目
### `del`
`del` 命令根據指定鍵刪除項目。
```python
>>> wife = {'name': 'Rose', 'age': 33, 'hair': 'brown'}
>>> del wife['age']
>>> wife
# {'name': 'Rose', 'hair': 'brown'}
```
## 檢查字典中的鍵
```python
>>> person = {'name': 'Rose', 'age': 33}
>>> 'name' in person.keys()
# True
>>> 'height' in person.keys()
# False
>>> 'skin' in person # 可省略 keys()
# False
```
## 檢查字典中的值
```python
>>> person = {'name': 'Rose', 'age': 33}
>>> 'Rose' in person.values()
# True
>>> 33 in person.values()
# True
```