# 全域變數與區域變數
>[!Warning] 陷阱:
>若變數是==串列、字典或集合(非int)==,則很容易遇到賦值的陷阱,當多個變數同時指向同一個串列、字典或集合時,只要被指向的變數內容被修改(注意不是用等號賦值),則可能多個指向其的變數內容也會跟著更動。
```python=
a = []
b = a
c = []
d = c
def f1():
a.append(1)
#global c,若加上這句則f2裡的c會受影響
c = [1]
print(a) # [1]
print(b) # [1] # 被影響
print(c) # [1]
print(d) # [] # 不受影響
def f2():
print(a) # [1] # 被影響
print(b) # [1] # 被影響
print(c) # [] # 不受影響
print(d) # [] # 不受影響
f1()
f2()
```
>f1 函式的 a 不受作用域的影響,使用 <font color="#f00">append</font>發生「改變」後,不論 a 在何處都會被影響,連帶 b 也被影響,但 c 因為是使用等號「宣告賦值」,就會轉變成「區域變數」,因此在f1的 c 就不會被影響,d 也不會被影響,不過如果在 f1 的開頭加上 global c,等同於將 c 從區域變數提升到全域變數,f2 裡的 c 就會被影響。
# 字串string
## 轉義
Python裡的轉義即是「跳脫字元」,使用「\」來進行特殊操作
如果在字串的前方加上「r」,表示這個字串為「raw string」,不要進行轉義,如\n若不轉義則不會進行換行,而是印出\n。
```python=
a = r'123\n456' # 123\n456
b = '123\n456'
# 123
# 456
```
## 字串操作
<font size="4">**結合字串**</font>
使用「+ 號」可以針對「變數」與「字串」進行結合。(注意字串結合若需要空格須自己補)
```python=
a = 'hello'
b = ' world' # 前方補上空格
c = a + b + '!!!' # hello world!!!
```
<font size="4">**重複字串**</font>
在字串後方使用「*」加上數字,可以指定該字串要重複幾次。
```python=
a = 'ok'*10
```
<font size="4">**取得字元與字串**</font>
如果要取得某一串文字,可以使用「slice」的方式,定義 slice 的方式為一組方括號、一個 start ( 開始順序 )、一個 end ( 結尾順序 ) 和一個中間的 step ( 間隔 ),常見的規則如下:
>[!Note]註 : end代表取到end的「前一個字元」
| 定義 | 說明 |
| -------- | -------- |
| [:] | 取出全部字元 |
| [start: ] | 從start位置取到最後一個字元 |
| [: end] | 從最一開始取到end的「前一個字元」 |
| [start : end] | 從start位置取到end的「前一個字元」 |
| [start : end : step] | 同上,但每次跳個step個字元 |
```python=
a = '0123456789abcdef'
print(a[5:-3]) # 56789abc ( 從 5 開始到倒數第 4 個( -3-1 ) )
print(a[5:10:2]) # 579 ( 從 5 開始到第 9 個,中間略過 2 個 )
```
<font size="4">**split()拆分**</font>
可將一個字串依照字串裡的「分隔符號」,拆分成串列(list),串列是指許多值組成的序列,內容使用逗號分隔。
```python =
a = 'hello world, I am oxxo, how are you?'
b = a.split(',') # 以逗號「,」進行拆分
c = a.split(' ') # 以空白字元「 」進行拆分(若未填符號預設以空白分隔)
print(b) # ['hello world', ' I am oxxo', ' how are you?']
print(c) # ['hello', 'world,', 'I', 'am', 'oxxo,', 'how', 'are', 'you?']
```
<font size="4">**字串替換**</font>
`replace()`函式有三個參數,(舊的字串,新的字串,替換的數量),若沒有指定數量則會將所有指定字串替換掉
```python=
a = 'hello world, lol'
b = a.replace("l","xxx") #a字串裡的「l」全部被替換成xxx
c = a.replace("l","xxx",2)
# hexxxxxxo world, lol ,前兩個「l」被替換
```
<font size="4">**搜尋和選擇**</font>
可適用`find()`,`index()`兩個函式,預設從字串左邊找起,找到指定字串或字元時,會回傳「第一次出現的位置」,如果沒有找到結果,則回傳-1
```python=
a = 'hello world, I am oxxo, I am a designer!'
a.find("am") #15,從左邊找起am第一次出現
a.rfind("am") #26從右邊找起am第一次出現(即整個字串最後一次出現am)
```
還有些許搜尋字串的方法
| 函式 | 說明 |
| -------- | -------- |
| startswith() | 判斷開頭字串(括號內填入判斷條件) |
| endswith() | 判斷結尾字串(括號內填入判斷條件) |
| isalnum()/isalpha() | 判斷是否只有字母或數字 |
| count() | 計算子字串出現了幾次 |
## 字串格式化
字串格式化即是在列印字串時可將整數、字串等變數傳遞至指定位置
<font color="#46A3FF">f-string</font>,操作方式為「f{變數名稱或運算式}」( 開頭可以使用 f 或 F ),輸出結果會將變數或運算式的內容,放入指定的位置。
```python=
a = " world"
b = "Jason"
c = f"Hello{a} I am {b}"
print(c) # Hello world I am Jason
```
## 更多操作
以下整理了更多常用字串操作,參考[文字與字串常用方法](https://steam.oxxostudio.tw/category/python/basic/string-all.html#a8)
# 串列(list)
串列 ( list ) 又稱為列表、清單或陣列(array),串列和元組 ( tuple ) 類似,都可以將任何一種物件作為它們的元素,即串列內元素型別可不一樣,形成一==有順序==的結構。
建立或相關操作可參考 [串列基礎操作](https://steam.oxxostudio.tw/category/python/basic/list.html)
## 串列的取值
* **多維串列**
```python=
a = ["banana","apple",["cat","dog"]]
print(a[2][0]) # cat
print(a[1][0]) # a,apple的第一個字元a
print(a[2][0][2]) # t,cat的第三個字元t
```
* **slice()**
如同字串的取值,以[start:end]來決定取出的值範圍
如果使用兩個冒號「::」,表示要「間隔幾個項目」取值,例如「::2」就是間隔兩個項目,如果是負數,就是從右側取值,因此「::-1」就可以讓反轉整個串列。
```python=
a = [0,1,2,3,4,5,6,7,8,9]
c = a[3::2] # 3,5,7,9,從第3個位置開始,每隔2取值
d = a[::-1] # 9,8,7,6,5,4,3,2,1,從最右側開始取回來
```
## 複製串列
使用「b=a」與<font color="#46A3FF">「b=a[:]」</font>的做法效果不同,前者實際上是a與b都指向同一個串列,所以若修改了a的內容b也會隨之更動,但後者是複製a串列成為一全新串列並指派給b,所以a、b互不干涉。
```python=
a = [0,1,2,3]
b = a
a[0] = 1
print(a) #1,1,2,3
print(b) #1,1,2,3
#------------------------
b = a[:]
a[0] = 1
print(a) #1,1,2,3
print(b) #0,1,2,3
```
## 添加串列
* **`append()`**
可將項目添加到一個串列的「尾端」
* **`insert()`**
insert(插入的位置,插入項目)
可指定串列的位置插入項目,若指定為-1則是插入在最後一個元素之前一個位置
>[!Important]重要:
>此是插入並不是取代,故位置要特別注意
```python=
a = ['a','b','c','d','e']
a.insert(3,100) # ['a','b',100,'c','d','e']
d = ['a','b','c','d','e']
d.insert(-1,100) # ['a','b','c','d',100,'e']
```
## 刪除串列
| 函式 | 說明 |
| -------- | -------- |
| del list[index] | 刪除某範圍內的項目,刪除後後方元素會向前遞補|
| remove(欲刪除項目) |刪除串列中第一次出現的此項目 |
| pop(指定位置) |取出並移除此位置的項目,若未指定位置則欲設最後一個 |
以下還有多種常用串列方法 [參考此處](https://steam.oxxostudio.tw/category/python/basic/list-2.html)
# 元組 ( 數組 ) tuple
tuple 與 list 類似都是儲存項目的「有序」容器,==且都允許不同型別的物件存在於同一 tuple==,但有些許不同,其餘操作部分與list類似
* tuple只要建立了就不能修改
* tuple使用 ( ),list則使用 [ ]
* 若tuple內只有一個元素,則後方須加上「逗號」
# 字典 dictionary
字典作為儲存資料的容器,與list、tuple 最大的不同就是字典中的項目==沒有順序性==,是按照鍵 key 的位置來做紀錄。
## 建立字典
**`dict()`**
```python=
dict1 = {'name':"Jason",'age':18,'eat':["apple","egg"]}
dict2 = dict(name = "Jason",age = 18,eat = ["apple","egg"])
#用dict()則key不須加引號,且使用 =
a = [['x','100'],['y','200'],['z','300']]
dict3 = dict(a) #也可將原本是list的變數變為dict
# 變為{'x':'100','y':'200','z':'300'}
```
## 讀取字典
注意兩種方法皆可,但若使用中括號[ ],若key值不存在則會發生編譯錯誤
```python=
a = {'name':"Jason",'age':10,'eat':["apple","egg"]}
print(a['eat'][0]) # apple,使用['key']來取值
print(a.get('name')) # Jason,使用get()取值
```
## 複製字典
**`deepcopy( )`**
copy( ) 的方法只能針對「項目內容不會發生變化」的字典,如果字典的「深層內容(list等)」會發生變化,就會出現複製項目也被改變的現象。
用法 : **複製字典 = copy.deepcopy(預備複製的字典)**
## 字典的排序
現如今有個字典:
director_count =
{'Christopher Nolan': 20,
'Nitesh Tiwari': 4,
'Makoto Shinkai': 4,
'Olivier Nakache': 4,
'Martin Scorsese': 20}
```python=
#針對字典的 value 進行降序排序
sort = sorted(director_count.items(),key = lambda x:x[1],reverse = True)
#此處 director_count.items() 結果就像個元組,
#像[('Christopher Nolan', 8), ('Nitesh Tiwari', 2)]
#因此 lambda 函式用 x[1] 代表第二個元素
```
<font size = 4>**max()**</font>
此函數可以對字典做最大值的查找
```python=
#dict = {'1':6,'2':8,'3':1}
max1 = max(dict,dict.get) #max1 = 1
max2 = max(dict) #max2 = 3
```
由此可知若 max()中有 get 函數,代表找的是 value 的最大值,若沒有則找的是 key 的最大值。
# 集合 (Set)
一個集合裡所有的鍵==都不會重複==,因為集合不會包含重複的資料的特性,常用來進行去除重複的字元、或判斷元素間是否有交集、聯集或差集之類的關聯性。
## 建立集合
* **set():**
可使用 **set( )** 將list、dict等轉換成集合,若遇到重複元素只會保留一個,且字典只會將鍵轉為集合元素
* 大括號 { }
```python=
a = {1,0,2,5,4,'h','c',False}
b = set("hello") # {'h','e','l','o'} 只保留不重複
```
## 其他語法
1. 加入項目 `add( )`:集合.add(項目)
2. 移除項目 `remove( )`:集合.remove(項目),不過如果該項目不存在,就會執行錯誤。
3. 移除項目 `discard( )`
4. 更新項目 `update(iterable)`
此方法更新集合裡的值,參數為可迭代的物件,如其他集合、字典、元組等,且 update()函數不返回值。
```python=
例如將 set2 內容更新到 set1
set1 = {1,2,3,4,5}
set2 = {4,5,8,9}
set1.update(set2) #set1 = {1,2,3,4,5,8,9}
```
## 交集、聯集、差集、對稱差集

使用集合運算有兩種方法,一種是使用特定的方法,另外一種則是使用「符號」( 集合運算子 )
| 集合 | 函式 | 運算子 |
| -------- | -------- | -------- |
| 交集 | a.intersection(b) | a&b |
| 聯集 | a.union(b) | a|b |
| 差集 | a.difference(b) | a-b |
| 對稱差集 | a.symmetric_difference(b) | a^b |
### issubet() 方法
判斷一集合 x 的所有元素是否都包含在集合 y 中,結果返回一個布林值
```python=
x = {"a", "b", "c"}
y = {"f", "e", "d", "c", "b", "a"}
z = x.issubset(y) # True
```
# if else
## 三元運算式簡化
可將if else判斷句簡化成一行表示,其語法為 <font color="#46A3FF">**行為1 if 條件1 else 行為2**</font>
```python=
a = int(input('輸入文字:'))
print("小孩") if a < 20 else print("大人")
```
# 生成式 ( Comprehension )
## 串列生成式
* 假如要產生一個1~9平方的list,可用 `[j*j for j in range(1,10)]`實現
```python=
#傳統方法
a = []
for i in range(1,10):
a.append(i*i) #a = [1,4,9,16,25,36,49,64,81]
#使用生成式串列
a = [j*j for j in range(1,10)]
```
* 兩層for迴圈也能實現
```python=
a = []
for i in 'abc':
for j in range(1,4):
a.append(i + str(j))
# ['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']
a = [i + str(j) for i in 'abc' for j in range(1,4)]
```
* 生成式串列搭配if使用
```python=
#建立一串列,將1~10中偶數加入串列中
a = []
for i in range(1,10):
if(i%2==0):
a.append(i) #[2,4,6,8]
#生成式串列做法,加上if
b = [i for i in range(1,10) if i%2==0]
#若if放在for前面,則須加上"else",以下將奇數變為100加入
c = [i if i%2==0 else 100 for i in range(1,10)]
#[100, 2, 100, 4, 100, 6, 100, 8, 100]
```
## 其餘生成式
* 字典生成式
`result = {key:value for item in iterable}`
* 集合生成式
`result = {value for item in iterable}`
```python=
#字典生成串列式
dict1 = {i:i*i for i in range(1,5)} #{1: 1, 2: 4, 3: 9, 4: 16}
#集合生成串列式
set1 = {i for i in range(1,5)}
```
# 匿名函式 lambda
lambda函式是 **「只有一行」** 的函式,可以用來代替一些小型函式,就可以不用用def額外新增程式碼片段,一般來說若想快速建立一個使用一次後就會丟棄的簡單函式就可以用lambda定義,常見的是搭配**map**使用,lambda有幾項特點:
* 不需要定義函式名稱
* 只能有一行運算式
* 匿名函式執行完後會自動回傳結果,而不需要加上return
lambda函式的定義是 <font color=" #6A6AFF">**func = lambda 參數1, 參數2, ... : 運算式**</font>,其中參數即為一般函式中需要輸入的變數,且使用一個變數去接收此匿名函式,即可像一般函式一樣使用並接收參數
>[!Important]重點:
>lambda 後接的為在撰寫普通函式時**要接收的參數**,以此去思考就很容易判斷後方要撰寫什麼
```python=
def a(x,y): #定義一函式計算 x 參數的 y 次方
return x**y
b = lambda x,y:x**y
print(a(2,3)) #8
print(b(2,3)) #8
(lambda x,y:x**y)(2,3) #也可以這樣呼叫
```
## 搭配if條件
使用if返回整數的絕對值
```python=
abs = lambda x:x if x > 0 else -x #lambda
print(abs(-5)) #5
```
## 搭配for
```python=
list1 = lambda n :[i for i in range(n)] #匿名函式設定參數為n,帶入後方的生成式
print(list1(5)) # [0,1,2,3,4]
```
## 搭配map
>[!Note] map語法:
>**x = map(function,iterable..)**,map會使用function的方法對迭代變數做運算
```python=
y = map(lambda x:x**2,[1,2,3,4,5])
print(y) #[1,4,9,16,25]
```