---
# System prepended metadata

title: Python 筆記

---

# Python 基礎介紹
## Python is Object-Oriented

Ｑ： 什麼是 object？
Ａ： 
<font color = "snake">Object</font> 基本上就是 ++a collection of data，和一些可以對這些 data 作用的 functions++。
幾乎所有會在 python 裡看到的東西都是 object，像是 data structures 如 strings, lists, arrays, dictionaries...，和這些各式各樣的 objects 一起的是可以對它們作用的各種不同的 methods。
> <font color = "snake">method</font>：可以作用在 object 上的 ++functions++。

舉例來說，假設我們有一個 string：

```python
c = "My dog's name is Bingo"
```

其中一個可以對 string object 作用的 method 叫做 <font color =  "green">`split()`</font>：

```python
c.split()
>>> ['My', "dog's", 'name', 'is', 'Bingo']
```
> `split()` 會對和它用 `.` 相連的 string `c` 作用，從空格處將這個 string 分割成（在這個例子中）五個分開的 strings，然後 return 一個包含這五個 strings 的 ++list++。

我們也可以在 `split()` 裡加上 argument，例如：

```python
c.split('g')
>>> ['My do', "'s name is Bin", 'o']
```
> 把 `c` 這個 string 從有出現 g 的地方切開

所以從這個例子我們知道 `split()` 是一種 string method，而除了 `split()` 以外，也有很多其他的 string methods。

Object 除了有 methods 以外，還有另個東西叫做 <font color = "snake">instance variables</font>，也就是++和這個 object 存在一起的 data++；如果我們把 ++methods 和 instance variables++ 一起看，它們兩個合稱 <font color = "snake">attributes</font>。

$\rightarrow$ 每一種 object（像是 strings, lists, arrays, dictionaries）都會有自己一個 set 的 attributes，而且這個 set 是 uniquely associated with 這個 object class。

舉例來說： `split()` 是 string 的 attribute，但不是 array 的 attribute。



# list / dictionary / tuple / set
## list

<font color = "snake">list</font>： 一個 python objects 的 collection，用 ++int++ 作為 index，從 0 開始。
- multidimensional lists and tuples

```python
a = [[3, 9], [8, 5], [11, 1]] 
print(a[1])
>>> [8, 5]
print(a[1][0])
>>> 8
```
> tuple 的概念也相同，只是 tuple 裡的東西不能改變。

### 建立 list

- 建立空 list
```python
mylist = []
```

- 建立一個具 n elements 的 list，其中 init value 皆為 0
```python
mylist = [0]*5
print(mylist)

>>> [0, 0, 0, 0, 0]
```

- 建立一個具 n elements 的 list，其中除了第一個 init value 為 -1，其餘皆為 0
```python
mylist = [-1] + [0]*4
print(mylist)

>>> [-1, 0, 0, 0, 0]
```

### 刪除 list 某些 index 的 element

如果沒有要 return 需要刪除的 element，我們可以用 `del`，如下面的例子，我們希望刪除 index 分別在 1 和 3 的 `'b'` 和 `'d'`：

```python
my_list = ['a', 'b', 'c', 'd', 'e']
indices_to_remove = [1, 3]
for index in sorted(indices_to_remove, reverse=True):
    del my_list[index]
print(my_list)  

>>> ['a', 'c', 'e']
```
> 首先我們先將要刪除的 index 利用 `sorted()` 排序，接著再一個一個刪除
> 
> $\rightarrow$ 須注意的是 <font color = "red">`reverse` 設成 `True`</font>，因為如果按照 index 小到大的順序刪除，在刪除 index 1 時，後面的 elements 會遞補過來，接下來刪 index 3 時就不是 `'d'` 而是刪到 `'e'` 了。

## dictionary
### 基本性質
<font color = "snake">dictonary</font>： 一個 python objects 的 collection，但是 index（也就是 keys） 可以是 strings / numbers。

$\rightarrow$ ++key++ 不見得要 int，甚至可以用 tuples，++幾乎任何 python object 都可以，只要這個 object 是 immutable （不會改變的），所以例如 list 就不能作為 key++。

例子：
```python
room = {"Emma":309, "Jake":582, "Olivia":764}
```
> 每個 dictionary 的 entry 用 `,` 分隔，每個 entry 包含一個 <font color = "snake">key</font> 和一個 <font color = "snake">value</font>，兩者用 `:` 分開。
> 
> $\rightarrow$ access dictionary entry 的方式和去 access list 類似，只是 list 是用 index，dictionary 則是用 key。

混合不同形式的 key 的例子：

```python=
weird = {"tank":52, 846:"horse", "bones":[23, 'fox', 'grass'], "phase":'I am here'}

print(weird[846])
>>> "horse"

print(weird["bones"])
>>> [23, 'fox', 'grass']
```
> 在 access dictionary 的 element 時，如果 key 是 int 就不需要 quotation，例如第三行我們用 `weird[846]` 而非 `weird["846"]`
> 
> 另一方面，如果 key 是 string 則需要 quotation，不管用 single quote `'` 或是 double quote `"` 都可以，這兩個是通用的（雖然習慣上會用 `"`）
> 
> $\rightarrow$ 即使我們在定義 dictionary entries 時，key 是用 double quote 包住，在 access 時打 single quote 也行，例如第六行的 `weird["bones"]` 改 `weird['bones']` 也可以得到一樣的結果。

### 建立一個 dictionary

建立一個空的 dictionary：
```python
d  = {}
```

有了空的 dictionary `d` 以後，我們可以加入一些 entries：

```python=
d["last name"] = "Alberts"
d["first name"] = "Marie"
d["birthday"] = "January 27"
print(d)
>>> {'last name': 'Alberts', 'first name': 'Marie', 'birthday': 'January 27'}
```
> 每一個 `d[]` 裡的東西，就好像我們去 access list element 時裡面是 index，只是對 dictionary 來說，我們的 index 就是 key，如第一行的 `"last name"` 是 key，後面的 `"Alberts"` 是這個 key 對應的 value。

### 利用 dictionary 計數

假設我們需要計算一個 list 裡的每個單字出現的次數，我們可以透過建立一個 dictionary，來存放每個單字（key）以及對應的出現次數（value）。

例子：

```python=
word_list = ['apple', 'banana', 'orange', 'apple', 'banana', 'apple']

word_counts = {}
for word in word_list:			# 對於每個在 word_list 裡的 element
    if word in word_counts:		# 我們都去檢查它是否已經存在於 word_counts 這個 dictionary 中
        word_counts[word] += 1		# 如果有，則增加它的 value（即出現次數）
    else:				# 如果 dictionary 中還未加入這個 word
        word_counts[word] = 1		# 把這個 word 加入 dictionary 中，並令它的 value（即出現次數）為 1

print(word_counts)

>>> {'apple': 3, 'banana': 2, 'orange': 1}
```
> `word_counts[word]` 代表的是在 `word_counts` 這個 dictionary 中， `word` 這個 key 對應到的 value。
> $\rightarrow$ 當使用 `word_counts[word]` 時，python 就會在 `word_counts` 這個 dictionary 中尋找 `word` 這個 key，然後再 return 它的 value。


### 利用 max 找出 dictionary 中最大的 value 及對應的 key

```python
my_dict = {'apple': 10, 'banana': 20, 'orange': 15}
max_key = max(my_dict, key=my_dict.get)

print("Key with the greatest value:", max_key)
print("Value of the key:", my_dict[max_key])

>>> Key with the greatest value: banana
>>> Value of the key: 20
```
> `max()` 的 parameter `key` 被設成一個 function `my_dict.get`，`my_dict.get` 會去取得 `my_dict` 這個 dictionary 中每個 key 對應的 value，藉由這個值，`max()` 會去比較每個 key 的 value，然後 return value 最大的 ++key++。
> 
> $\rightarrow$ 雖然說 `max()` 會 return 一個 iterable 中最大的「值」，但不代表我們在此 return 並 assign 給 `max_key` 的，會是某個 key 的 value（也就是 `max_key` 為 `banana` 而非它的 value `20`）
>> 因為在此使用 `max()` 時，它針對的 iterable 是一個 dictionary `my_dict`，而在 iterate through 一個 dictionary 時，預設是 iterate over keys。
>> 因此，當我們在將 `key` 設成 `key=my_dict.get` 時，也就代表了每個 dictionary 的 key 都已經被賦予了它的 value 作為比較的基準，所以最後 `max()` return 的「最大值」仍是一個 key。 



## tuple
<font color = "snake">tuples</font>： 不能改變的 list，用 ``()`` 表示

## set

set 的長相：
```python
this_is_a_set = {1, 'apple', (2, 3), 4.5}
```
$\rightarrow$ set 由大括號 `{}` 表示
$\rightarrow$ 裡面的 element 可以是不同的 type，如此例中四個 element 的 type 依序為：int, str, tuple, float


- Note： 雖然 set 是由大括號 `{}` 表示，但是在建立空 set 時不能如建立空 list 一樣 `new_empty_list = []` 令 `new_empty_set = {}`

> $\Rightarrow$ 因為會被認為是一個空的 dictionary

因此建立一個空 set 需用： `new_empty_set = set()`

### set 特性：

- <font color = "green">unordered</font>
> $\rightarrow$ 因此無法用 index 去 access set 裡面的 element
>> 例如對 list 可以： `target = mylist[0]`
>> 
> $\rightarrow$ 也無法用 slicing
>> 例如對 list 可以： `newlist = oldlist[3:6]` 
- set 中的 <font color = "green">elements unique</font>
> $\rightarrow$ 所以重複將相同的 element 加入 set 的動作會被 ignore
>> 例如重複將 `"apple"` 加入 set 兩次，最後 set 中只會有一個 `"apple"`：
```python
myset = set()

myset.add("apple")
print(myset)

myset.add("apple")
print(myset)

>>> {'apple'}
>>> {'apple'}
```

### set 用途

- set 經常用來檢驗++是否存在 duplicate++，例子如下：

```python
def has_duplicate(nums: list[int]):
    seen_numbers_set = set()
    for num in numbers_list:
        print("\ncurrent number examined is:", num)
        if num in seen_numbers_set:
            print("Exists duplicate")
            return True
        seen_numbers_set.add(num)
        print("Current seen numbers set is:", seen_numbers_set)
    return False

numbers_list = [1, 4, 5, 6, 2, 3, 1]
ans = has_duplicate(numbers_list)
print("Duplicate in this list?", ans)
```

output：

<img src= "https://hackmd.io/_uploads/B1oL1j_W0.jpg" alt=output width="70%">




# 一些常用的 functions

## 獲得 input

獲得 input 的兩種方式，一個是用 `input` 讓 user 輸入，另一種是用 `loadtxt` 讀檔案（像是 txt 檔、csv 檔）進來。

### input

Python 有一個 function 叫作 `input`，可以從 user 那邊拿到一個 input，然後 assign 這個 input 一個變數名稱。例如：

![image](https://hackmd.io/_uploads/Syama87b0.png)


當我們執行到這行 `input` function 時，螢幕上就會顯示 input 括弧內的 string argument：

![image](https://hackmd.io/_uploads/HkU3h87ZR.png)


然後等待 user 輸入 input，而我們得到的 input 會被 assign 到 `distance` 這個變數。假設 user 輸入 `450`，那麼：

![image](https://hackmd.io/_uploads/H1xg6IQbA.png)

$\rightarrow$ 如果我們想把得到的 input 變成小數，只要加上 `float()` 就行：

```python
distance = float(input("Input trip distance(miles): "))
```

### loadtxt

#### 從 txt 檔讀 input

假設我們有一個檔案叫做 `mydata.txt`，裡面可能有一些實驗資料和相關資訊長這樣：

```=
Data for experiment
Date: 16-Aug-2016
Data taken by L and J

data point time(sec) height(mm) uncertainty(mm)
	0	0.0	180		3.5
	1	0.5	182		4.5
	2	1.0	178		4.0
	3	1.5	165		5.5
```

我們想把這些資料裡的每一行都讀進一個對應名字的 array 裡面，其中一個作法就是用 NumPy 的 `loadtxt` function：

![image](https://hackmd.io/_uploads/H1WS55mWR.png)

例子：

```python
dataPt, time, height, error = np.loadtxt("mydata.txt", skiprows = 5, unpack = True)
```

此處的 `loadtxt` 用了三個 arguments：

1. 檔案名稱的 string
> 也就是例子中的 `"mydata.txt"`
2. 檔案的最前面（也叫做 <font color = "snake">header</font>）要跳過幾行
> 此例中，因為前五行非 data 本身的內容，所以跳過
3. 如果 `unpack = True` （預設為 `False`），每一行會被拆成分開的 array，如果設 `unpack = False`，所有讀到的 data 會在同個 array 中。
> 此例中，因為 `unpack = True`，所以我們可以按照這四行資料拆成四個 array。
> 
> $\rightarrow$ 如果用預設的 `unpack = False`
> 
> ![image](https://hackmd.io/_uploads/H1SHei7bA.png)
> 
> 結果會是：
> 
> ![image](https://hackmd.io/_uploads/HyCOxi7bC.png)



- Note：這裡的 `dataPt`, `time`, `height`, `error` 的 type 都是 numpy array 而非 lists，我們可以看下方的 code：

![image](https://hackmd.io/_uploads/BkpPC5Qb0.png)

印出來長這樣：

![image](https://hackmd.io/_uploads/rJdC09X-C.png)

一樣可以用 access list 的 index 方式，例如：

![image](https://hackmd.io/_uploads/B123JsQZ0.png)

結果會是：

![image](https://hackmd.io/_uploads/SySRyoX-R.png)

## 刪除

### del

用於刪除 list 中特定 index 的 element，且不需要 return 被刪的東西時。
> 如果刪除的同時要 return 被刪的 element，可以用 `pop()`

直接看例子：

```python
my_list = [1, 2, 3, 4, 5]
n = 2
del my_list[n]
print(my_list)

>>> [1, 2, 4, 5]
```

- Note： 因為 `del` modifies list in place，所以如果有一個情況是我們有一個 list A，然後我們++把 list A 的內容 assign 給 list B++，那麼<font color = "red">當我們對 list A 做 `del` 時，list B 的值也會跟著更改</font>，例子如下：

```python
list_A = [1, 2, 3]
list_B = list_A
del list_A[0]
print("List A: ", list_A)  # Output: [2, 3]
print("List B: ", list_B)  # Output: [2, 3]

>>> List A: [2, 3]
>>> List B: [2, 3]
```
> $\rightarrow$ 因為 `list_A` 和 `list_B` refer 到 memory 裡的同個 list object，所以對 `list_A` 做的更動對 `list_B` 來說也是 visible 的。

如果我們不希望在 `del list_A[0]` 時也一起改到 `list_B` 的內容，我們可以使用 <font color = "green">`copy()`</font> 將 `list_B = list_A` 改成 `list_B = list_A.copy()`，如下：

```python
list_A = [1, 2, 3]
list_B = list_A.copy()
del list_A[0]
print("List A: ", list_A)  
print("List B: ", list_B)

>>> List A:  [2, 3]
>>> List B:  [1, 2, 3]
```

### 刪除特定類型字元： join

例子：

用 `join()` 刪除所有不是英文的 character

```python
original_string = "Hello, 123world!"

result_string = ''.join(char for char in original_string if char.isalpha())
print(result_string)  

>>> Helloworld
```
> `join()` 會 iterate 過所有 `original_string` 裡的 character，對每個 char，我們會 call `isalpha()` 來檢查是否為英文字母，如果是的話， `join()` 會 concatenate 這些字母，再 return 單一的一個 string。

- `join()` 的 syntax：

```python
string.join(iterable)
```
> `iterable` 如 list, tuple...是你要拿來 concatenate 的東西；而 `string` 則是一個 separator，也就是你在 concatenate 各個 elements 時，每兩個中間的要插入的東西（例如空格）舉例來說：

```python
words = ['Hello', 'world', 'how', 'are', 'you?']
result_string = ' '.join(words)
print(result_string) 

>>> Hello world how are you?
```
> 在這個例子裡，`string` 是一個空格 `' '`，所以在把 `words` 這個 iterable 裡的每個 string concatenate 時，中間都會插入一個空格。

Note：
- `join()` 是 call on `string` 
- `join()` 通常用在要 concatenate 大量的 strings，來避免用 `+` 來 concatenate 的 performance overhead。


#### 反向 concatenate

一種常見的題目是把一個句子裡所有的單字反向再 output，這種時候一個作法是可以先將句子切割成單字（用 `split()`，用法可參考下方 `split()` 小節。）接著再用 slicing 反向，如下方例子：

```python
my_list = ['apple', 'banana', 'orange']
result = ' '.join(my_list[::-1])
print(result)  

>>> 'orange banana apple'
```
> `my_list[::-1]` 是一種 slicing 的 operation，會++產生++原本 list `my_list` 的反向 ++copy++，其中方括弧中的內容為<font color = "green">`[start:stop:step]`</font>：
>> 第一個 `:` 前的數字（start）代表從哪裡開始
>> 第二個 `:` 和第一個 `:` 之間的數字（stop）代表結束的位置
>> 第二個 `:` 後的最後一個數字（step）如果是正的，代表多少一個間隔，如果是負的則是反向
>> 
> 因此，此處即反向的去 `join()` `my_list`，每個 element 在 concatenate 時中間插入一個間隔 `' '`，並且因為沒有設定 start 和 stop，所以會從最後一個 element traverse 到第一個。



## 排序

### sort

`sort()` 會 sort in place，也就是會 modify 原本的 list

$\rightarrow$ 如果不想要更動到原本 list 的內容，可改用 `sorted()`（見下一小節）

```python
my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5]
my_list.sort()
print(my_list) 

>>> [1, 1, 2, 3, 4, 5, 5, 6, 9]
```

### sorted

```python
my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5]
sorted_list = sorted(my_list)
print("The original list is: ", my_list)      
print("The sorted list is: ", sorted_list)  

>>> The original list is: [3, 1, 4, 1, 5, 9, 2, 6, 5] 
>>> The sorted list is: [1, 1, 2, 3, 4, 5, 5, 6, 9]
```
> $\rightarrow$ 原本的 `my_list` 內容不會隨著 `sorted()` 的使用而改變。

- `sorted()` 的 syntax：
```python
sorted(iterable, *, key=None, reverse=False)
```
> - iterable： 可以是如 list, tuple, string...
> - key (optional)： 即排序的依據，是一個會對每個 iterable 的 element 作用的 function，預設為 `None`，即用 natural order 排序。
>> 其餘常見的 key 使用方式可參考下方 lambda 小節
>> 
> - reverse (optional)：預設為 `False`（由小到大），如果設為 `True` 則為由大到小排序。

### 更改排序依據： lambda

`lambda` 是一種 function 的 keyword，通常在當我們想要快速使用一個簡單的 function，卻又不想再多去定義一大個 code block 時用。舉一個很常見的例子：

```python
my_list = [(1, 'b'), (2, 'a'), (3, 'c')]
sorted_list = sorted(my_list, key=lambda x: x[1])
print(sorted_list)  

>>> [(2, 'a'), (1, 'b'), (3, 'c')]
```

在這個例子裡面，`lambda x: x[1]` 就是一個 lambda function，它的 argument `x` 代表了 `my_list` 裡的每個 tuple，而這個 lambda function 會 return 的就是每個 tuple 的 index 1 項 `x[1]`。

這裡我們用到這個 lambda function 是因為我們想要根據 `my_list` 裡每個 tuple 的第一項去 sort，所以我們將 lambda function 的 return value `x[1]` 設成排序依據的 key。

- lambda function 的 syntax：
```python
lambda arguments: expression
```

- Note：
	- lambda function 是 ++user-defined++ function，並非一些 predefined 的 functions
	- lambda function ++只能有一行++，如果需要 define 的 function 太複雜，需要多行，就還是該用 `def` 去完整定義另外一個 function。
	- lambda function ++可以有多個 arguments++，每個用 `,` 分隔，舉例來說：

```python
lambda x, y: x + y
```
> $\rightarrow$ 這個例子中的 lambda function 有兩個 arguments `x` 和 `y`，然後會 return 他們的和 `x + y`

## 數值大小、界線
### min

syntax：
`min(iterable, *iterables, key, default)`
> $\rightarrow$ 後面三者為 optional
> - <font color = "green">iterable</font> 如 list, tuple, set, dictionary...
> - <font color = "green">\*iterables</font> 即可以有多個 iterables
> - <font color = "green">key</font> 為某個 function，我們去比較求 min 即基於這個 function 回傳的值
> - <font color = "green">default</font> 即如果我們的 iterable 為空，預設的回傳值

舉例來說，如果有一個 list 裡面每個 element 都是 string，我們希望求這個 list 裡最短的 string：

```python
my_list = ["apple", "banana", "pear"]
shortest_string = min(my_list, key = len)
print("Shortest string:", shortest_string)

>>> Shortest string: pear
```

$\rightarrow$ 如果沒有特別 specify 我們的 string 的比較基準是長度，那麼比較基準就是首個字母的 alphabetical order，同上面例子的 list：

```python
my_list = ["apple", "banana", "pear"]
smallest_string = min(my_list)
print("Smallest string:", smallest_string)

>>> Smallest string: apple
```

也可以用在常見的求一個 list 裡最小的數：

```python
numbers = [0,22,101,8,44]
print(min(numbers))

>>> 0
```

### range

`range(n)` 產生一個從 0 到 n （但不包含 n）的數列。

```python
list(range(0,10,2))
>>> [0, 2, 4, 6, 8]
```
> - 只有在要把 `range(n)` 的結果 print 出來時需要先用 `list()` 把產生的數列轉換成 list
> 
> $\rightarrow$ `range()` 的三個 parameters 依序為 <font color =  "green">start, stop, step</font>，也就是從哪個數字開始、到哪個數字（但不包含此數）、每次跳的值為多少

如果我們把 step 設成負數，就會產生一個由大到小的數列，例如：

```python
list(range(10,0,-2))
>>> [10, 8, 6, 4, 2]
```

如果要創造一個遞減的數列，另個方法是用 `reversed()`，例子如下：

```python
list(reversed(range(0,10,2)))
>>> [8, 6, 4, 2, 0]
```

- `list(range(0))` 會 output `[]`（empty list）
- `list(range(-10))` （任何負數）會 output `[]`（empty list）


## split

用來將一個 string（常用如對一個句子或一個段落），切割成一個一個單字，最後會 ++return++ 的是切好的一個個單字的 ++list++。
> 其實正確的來說也不一定是單字，而是（預設）會根據遇到空格或分行的地方去切。

舉例來說：

```python
sentence = "This is a sentence."
words = sentence.split()

print(words)  
>>> ['This', 'is', 'a', 'sentence.']

```


- `split()` 的 syntax：

```python
str.split(sep=None, maxsplit=-1)
```
> - `str`：要拿來 split 的 string 名稱
> - `sep` (optional)：要拿來切割的分界依據，如果沒有特別更改，預設為遇到 whitespace characters（空格、tab `\t`、換行 `\n`），可以特別指定某個字母、符號⋯⋯去作為分界依據，例如：

```python
date = "2022-04-19"
parts = date.split('-')
print(parts)  

>>> ['2022', '04', '19']
```
> - `maxsplit` (optional)： 最多可以++切幾次++，所以假設 `maxsplit=2`，那麼會最多只能切出<font color = "red">三</font>個 element。預設為 `-1`，也就是對切的次數沒有限制。
> 例子：

```python
sentence = "This is a sentence."
words = sentence.split(maxsplit=2)
print(words) 

>>>['This', 'is', 'a sentence.']
```

Note： ++`split()` 的 `sep` 只能設定一個++，因此，如果有多種符號需要作為劃分依據，一個方法是可以先換成同一種。例子：

```python
date = "2024,05-06 12:51"
date_number_only = date.replace(',',' ').replace('-', ' ').replace(':', ' ')
numbers = date_number_only.split()
print(numbers)

>>> ['2024', '05', '06', '12', '51']
```
> $\rightarrow$ 可以一次對同個 string 連結多個 `replace()`

## lower

`lower()` 可以把所有大寫英文字母轉換成小寫，如果本身即是小寫的 char 則不變，非英文字母的 char（如數字）也不變。

例子：

把一個 list 裡的每個 string 轉換成小寫

```python
words = ['Hello', 'WORLD', 'How', 'Are', 'You?']
lowercase_words = [word.lower() for word in words]
print(lowercase_words) 

>>>['hello', 'world', 'how', 'are', 'you?']
```

例子：

如果遇到數字、逗號驚嘆號等符號不變

```python
string = "Hello, 123world!"
lowercase_string = string.lower()
print(lowercase_string)  

>>> hello, 123world!
```