# Python 3 語法大全
<br>目錄 (點擊可以跳轉)
* <a href=#variable>變數及型態轉換</a>
* <a href=#operator>運算子</a>
* <a href=#inout>輸入輸出</a>
* <a href=#if>條件判斷式(if)</a>
* <a href=#loop>迴圈(Loop)</a>
* <a href=#container>容器</a>
* <a href=#string>字串處理</a>
* <a href=#function>函數</a>
* <a href=#mod>模組</a>
* <a href=#file>檔案處理(IO)</a>
* <a href=#exception>例外處理</a>
* <a href=#class>類別(class)</a>
## <p id = "variable">變數及型態轉換</p>
在Python每個東西都是物件(Object)
<br>
### 變數
**宣告變數方法:**
<br>**變數名稱 = 值**<br>
<br>名稱限制:
* 第一個字母必須是英文或_(底線)或中文(不建議)
* 剩下只能是英文、中文(不建議)、_(底線)或是數字,不可以使用其他符號
* 不能為關鍵字,如果使用了可能會造成,原來的關鍵字無法正常使用
<br>宣告一個整數
```
x=100
```
<br>宣告一個布林值(bool,真假值)
```
y=True
```
<br>宣告一個字串(String)
```
a="I am string1"
b='I am string2'
```
使用**del**可以刪除變數,讓其從記憶體消失
```
a=42
del a
```
### 型態轉換
可以將變數或資料轉換為你需要的型態,前提是要可以轉換
使用type()可以得知變數的型態
舉例:
* int() 將物件轉成int型態
* str() 將物件轉成string型態
* list() 將物件轉乘list容器型態
範例
```
a=10
b='95'
c=(4,2,3,8,9)
print(type(a),type(b),type(c),sep='\n')
a=str(a)
b=int(b)
c=list(c)
print(type(a),type(b),type(c),sep='\n')
```
輸出結果:
```
<class 'int'>
<class 'str'>
<class 'tuple'>
<class 'str'>
<class 'int'>
<class 'list'>
```
### 全域變數vs區域變數
一般我們宣告使用的變數為全域,而像是函式的參數或是函數內部宣告的變數就是區域變數
兩者的差別
區域變數:當離開宣告所在的區塊,會從記憶體中釋放,因此不能在區塊外使用,所以不同區域內部的變數可以名稱相同
全域變數:一直存在直到全部程式跑完
當在區域(例如函數裡面)內,有區域變數和全域變數同樣名稱時,會優先使用區域變數。
---
## <p id="operator">運算子</p>
運算要先有運算式
### <br>運算符號
* **+** 加號
* **-** 減號
* **/** 除法
* **//** 整數除法只取商,餘數捨去
* **%** 除法,取餘數
* <b>*</b> 乘法
* <b>**</b> 指數
```
a=4**5 #a=1024
b=a+6 #b=1030
```
### 複合指派運算子
形式: 變數(任一運算子)=值
即為 變數=變數 運算子 值
```
a=10
a/=5 #a=a/5 a=2
```
### <br>關係運算子
關係運算子用於判別真假值後回傳真假值(bool),通常用於條件判斷,例如if或while<br>
關係運算子符號
* **==** 相等
* **!=** 不相等
* **>** 大於
* **>=** 大於或等於
* **<** 小於
* **<=** 小於或等於
* **is** 兩個東西是否為本質一樣,或是說是否共用同一塊記憶體
* **and** 可以用來串聯兩個判斷式,當兩個判斷式為True,回傳True
* **or** 可以用來並聯兩個判斷式,當兩個判斷式至少一個為True,回傳True
* **not** 當判斷式為False,就回傳True
```
5>10 #False
8<=10 #True
a=10
b=a
a is b #True
```
### 補充內容
問題一:
當兩個整數(a和b)本質一樣後,為什麼b改變不會影響a?
```
a=10
b=a
a is b #True
b=100 #b=100 a=10
```
原因:
Python不像c語言(靜態語言)一樣。
事實上,a變數指向的是為10的物件,所以當一開始b=a,代表b也指向了這個相同物件,因此本質上相同,然而將b=100,就是使b指向了另一個為100的物件,因此a不會隨b而改變。
<br>
問題二:
當兩個整數令為相同值,為什麼會本質一樣(指向相同記憶體位置)?
```
a=50
b=50
a is b #True
```
原因:
Python的資料物件,有分為兩種,而整數是屬於不可變的資料型別,下面將介紹Python的資料型別
### Python的資料型別
1. 可變的資料型別(ex:List,Dict)
可變即代表對同一物件值是可變的,因此當值改變,變數依舊指向同一物件
2. 不可變的資料型別(ex:Int整數,float浮點數,String字串,Tuple)
不可變即代表對同一物件值是不可變的,因此當值改變,變數必須指向到新創建的物件,且每個物件的值不會重複,當物件沒被指向,即會收回記憶體,所以**問題二**的原因就是因為,整數為不可變的資料型別,因此當都令為同一個值的時候,會指向同個物件,此外也能節省記憶體空間。
<br>
---
## <p id=inout>輸入輸出</p>
### 輸入
**input('請輸入資料:')**
括號內可放字串作為說明文字,此外輸入後的型態必為String
**eval():將字串變成數字**
可以把字串轉成數字(整數或小數),若字串不為完全的數字無法轉換並error
此外還可以執行使用者輸入的指令
範例
```
a=input("請輸入指令:\n")
eval(a)
```
輸入
```
print('hello world!')
```
輸出結果
```
hello world!
```
**str():將數字變成字串**
可以把數字轉成字串
### 一般輸出(print)
print(value,sep=' ',end='\n',file=sys.stdout,flush=False)
這些參數都能自己設定
**value**可以放多個並用,隔開
**sep**預設為半形空白,當輸出很多不同資料時,中間會輸出的字串,用於隔開不同值
**end**預設為一個換行(\n),當輸出完所有值後,要作為結尾的字串
**file**預設為sys.stdout(螢幕),用於設定輸出裝置
**flush**預設為False,決定是否在執行完print後,立刻輸出,而不是放在緩衝區,等同一區塊程式都輸出後,才一起輸出,在迴圈時會需要注意。
**範例**
```
print('Hello','world',sep='\n',end='!!!')
```
輸出
```
Hello
world!!!
```
### 格式化輸出(print)
如果面對,字串與變數交錯的印,可以更方便的輸出,使用方法為在要印出的字串裡面要印變數的地方加上格式詞,然後在字串後加上%(),括號內放入變數,若多個照順序並用逗點隔開
此外sep和end都可以搭配使用
**格式詞**
根據變數類型選擇對應格式,否則可能會出錯
* **%d** 以十進位整數方式輸出
* **%f** 以十進位浮點數方式輸出,**%.Xf** X可以為0~6,即可以決定印到小數點後幾位,然後四捨五入
* **%%** 在字串中顯示%的方法,否則只打一個會被認為是格式詞沒正確輸入
* **%s** 以字串(str())輸出,變數只要能用str()傳換就能印,**%.Xs**X的大小代表字串要從頭印幾個字元出來
* **%e,%E** 將浮點數以科學記號輸出
* **%o** 以八進位整數方法輸出
* **%x,%X** 以十六進整數方式輸出
* **%c** 以字元方式輸出
* **%r** 以字串(repr())輸出,變數只要能用repr()轉換就能印,在某些時候會跟用%s輸出結果不同,例如在同樣輸出字串時,%r會再該字串左右加上上下引號
**對齊技巧**
**Y+格式詞**
格式詞可為任何
Y為一個數字,Y>0為靠右對齊,Y<0為靠左對齊,Y及代表最少的半形空格數,若印的內容超出則不理會,若沒超出且Y為正數則會補空格在輸出的左邊,反之為補空格在右邊,所以若想完全對齊要確保Y大於等於最大的可能輸出長度
此外在Y>0的時候,Y左邊加上0可以使空白部分全補成0
另一種方法(用米字號代替):
```
b=10
print('%*d'%(b,a))等於print('%10d'%(a))
```
範例:
```
a=30
string1='apple'
b=679.42387
print('%5d\n%3o\n%x'%(a,a,a),end='\n\n')
print('str():%s\nrepr():%r'%(string1,string1),end='\n\n')
print('%1.3f\n%10.4f\n%10.1f'%(b,b,b))
print('%-10d'%a,'%-10.3s'%string1,sep='<---\n',end='<---\n')
print('%010.1f'%b)
```
輸出結果:
```
30
36
1e
str():apple
repr():'apple'
679.424
679.4239
679.4
30 <---
app <---
00000679.4
```
### 使用dict進行格式化輸出
可以使用當格式輸出的變數,但key值必須為字串
範例
```
mydict={'a':'apple','ba':42.8664,'s':10}
print('%(a)s,%(s)d,%(ba)7.2f'%mydict)
print('%(a)s,%(s)d,%(ba)7.2f'%{'a':'apple','ba':42.8664,'s':10})
```
輸出結果:
```
apple,10, 42.87
apple,10, 42.87
```
## <p id = "if">條件判斷式(if)</p>
使用if可以用來決定程式的執行方向,並達到跳躍執行程式的效果
此外執行的程式碼必須使用4個空白或是一次tab來縮排,所以可以來看縮排得知是否為同一層程式碼,而同一層和同一個if的else只能有一個
### **單層if**,else部分可以不需要
```
if 判斷式:
當判斷式為真(True),執行的程式碼
else:
當判斷式為假(False),執行的程式碼
```
```
if a>b:
print('a大於b')
else:
print('a小於b')
```
### **elif用法**
```
if 判斷式1:
當判斷式1為真(True),執行的程式碼
elif 判斷式2:
當判斷式2為真(True),執行的程式碼
else:
當以上判斷式都為假,執行的程式碼
```
範例
```
if 5>10:
print('a')
elif 5>3:
print('b')
else:
print('c')
```
輸出
```
b
```
若將elif分開....
範例
```
if 5>10:
print('a')
else:
print('c')
if 5>3:
print('b')
else:
print('c')
```
輸出
```
c
b
```
### **多層(巢狀)if**
```
if 10>5:
if 10>10:
print('a')
if 10>8:
print('b')
else:
print('c')
```
---
## <p id="loop">迴圈(Loop)</p>
迴圈可以重複執行某段程式碼
### **for迴圈**
通常用在知道迴圈要跑的次數用for迴圈
執行的程式碼也要縮排或是空白4格
宣告一個跑n次的迴圈,i可替換為任何已存在變數
```
for i in range(n):
print(i);
```
其他宣告方法:
根據給的容器(迭代器)大小跑迴圈(以下範例的容器的大小為4)
```
for i in [5,3,1,2]:
print(i) #印出i的值
```
輸出結果:
```
5
3
1
2
```
**range()**
**使用方法一:**
range(n)
代表產生一個容器裝有0到n-1,共n個數字
**使用方法二:**
range(起始值(預設為0),終止值,每次增加的量),若省略不打增加的量則預設為+1
範例
```
for i in range(20,10,-2):
print(i)
```
輸出結果:
```
20
18
16
14
12
```
### **while迴圈**
通用於不能保證迴圈要跑幾次時使用
```
while 判斷式:
判斷式為真時,執行的程式碼
```
範例
```
a=0
while a<=40:
a+=10
print(a)
```
輸出結果:
```
10
20
30
40
50
```
**巢狀迴圈**
使用for時,要注意變數,不要重複使用同樣變數(i)來跑,否則會造成迴圈出意外
此外要注意內部圈跑完才會回到外部迴圈
```
while 判斷式1:
判斷式1為真時,執行的程式碼
While 判斷式2:
判斷式2為真時,執行的程式碼
```
範例
```
for i in range(3):
for j in range(i):
print('hello')
print('next loop~')
```
輸出結果:
```
next loop~
hello
next loop~
hello
hello
next loop~
```
<br>
**break**
如果想在迴圈還沒跑完前就立即終止它(立即終止代表break後面的待在同層的程式碼也不會被執行),可以使用break,通常可以搭配if使用
此外break只會終止自己待在的那層迴圈,而不會將整著巢狀迴圈都終止
範例
```
a=0
while(True):
if (a>5):
break;
print(a)
a+=1
```
輸出結果:
```
0
1
2
3
4
5
```
<br>**continue**
如果想跳過一次迴圈內部(跳過continue後面迴圈內部的程式碼)的執行可以使用continue,通常搭配if使用
範例
```
for i in range(4):
if i==2:
continue
print(i)
```
輸出結果:
```
0
1
3
```
---
## <p id="container">容器</p>
容器是用來放置東西(可以同時放不同種東西),而每種容器都有著不同特性以及不同方法(透過容器的自訂(變數)名稱加上.加上要呼叫的方法ex:a.add(),此外只要是方法(function)都要加上小括號)
### 容器通用方法(其實有些容器只能使用下列部分方法)
**容器名稱[]** 可以取內部的值
**len(容器名稱)** 可以知道內部的長度(大小)
**iter(容器名稱)** 會根據容器類型,建立其專屬的迭代器,可以用於要跑完一遍(尋訪)容器內部的for迴圈,若用在dict,則是以key值建立(**若物件是Iterable,可以不用建立迭代器,也可直接尋訪**)
**物件 in 容器名稱** 檢查物件是否在容器中,回傳布林值(如果用在dict則是查key值是否存在)
**del 容器名稱[index值(key)]** 刪除在那index值的東西,若容器是dict,則刪除對應於key的value值
**迭代器使用範例(好處在於可以不用知道容器大小就可以走遍(尋訪)容器)**
```
a=(3,2)
for item in iter(a): #尋訪tuple,iter(a)的部分可以直接換成a
print(item,' ',end='')
print()
b=[4,3,2]
for item in iter(b): #尋訪list,iter(b)的部分可以直接換成b
print(item,' ',end='')
print()
c={2,5,'apple'}
for item in iter(c): #尋訪set,iter(c)的部分可以直接換成c
print(item,' ',end='')
print()
d={'a':5,6:'i'}
for item in iter(d): #尋訪dict,iter(d)的部分可以直接換成d
print(item,' ',end='')
print()
```
輸出結果:
```
3 2
4 3 2
apple 2 5
a 6
```
**小技巧**
(在使用官方IDE)此外當容器被建立可以打上容器的變數名稱加上.並按下tab即能看到所有的可用方法,並使用上下鍵即能自動打上方法,**此方法適用python任何物件**
![](https://i.imgur.com/NN1kq3p.png)
左邊是文字編輯模式(每次需先Run過打上的程式碼,才能正常用tab,否則它無法辨識為正確的物件類別),右邊是Shell
<br>**容器比較**
![](https://i.imgur.com/sussjJN.png)
**勘誤3.6版(含)之後dict是有順序性的**
### <br>**tuple序對**
特性:有順序性,一旦建立無法修改內部內容
範例(可以使用[0]來回傳第0位的位置的值,使用[1]則就是回傳第1位的位置值,以此類推)
```
t=(4,2,3,'7')
print(t[0])
print(t[1]+t[2])
print(t[3])
```
輸出結果:
```
4
5
7
```
**tuple的方法(function)**
**index()**
從頭尋找出現在tuple的值,並回傳第一個出現的index值(位置),**找不到會直接跳錯誤訊息**
使用方法:
index(n)代表在容器的最大範圍內找第一個出現n的index值
index(n,a,b)代表在容器的index為a到index為b的範圍(不含b)找第一個出現n的index值
**count()**
回傳值在tuple內出現的次數
使用方法:
count(n)代表找n在tuple出現的次數
範例
```
a=(4,8,1,4,4)
print(a.index(1))
print(a.index(1,0,3))
print(a.count(4))
```
輸出結果:
```
2
2
3
```
### **list串列**
特性:有順序性,可以增加,刪除,修改內容
範例(也可以使用[]來得知特定位置的值)
```
a=['mouse',4,5,'apple']
print(a[0])
print(a[2])
```
輸出結果:
```
mouse
5
```
**list的方法(function)**
**append()**
在list的最後面加上一個資料成員(物件)
使用方法:
append(n)代表把n加到list最後面
**extend()**
在list的最後面加上一有順序的物件(容器)
使用方法:
extend(n)代表把容器n加到list最後面
**clear()**
將list內清空,只留下殼
使用方法:
clear()
**insert()**
將資料成員插入指定的index值(位置)
此外,若放的位置
使用方法:
insert(i,n)代表將n放到index值為i的位置
注意:
**若i為大於現有最大index值**,則會被放到最後面
**若i為負數則代表放到從後面數來i+1的位置,若已經倒數到index為0,則就放到第0位**例如:i=-1則代表放到倒數第二位
**remove()**
從頭開始,找指定的值,找到的第一個,將它移除
使用方法:
remove(n)代表,從頭開始找n,找到的第一個將它移除
**pop()**
將指定index值(位置)的值移除,並回傳被刪除的值
使用方法:
pop()代表,刪除最後一個位置的值並回傳值
pop(i)代表,刪除index(位置)為i的值並回傳值
**copy()**
將list複製並回傳
使用方法:
copy()代表複製list,並回傳複本
**index()**
從頭尋找出現在list的值,並回傳第一個出現的index值(位置),**找不到會直接跳錯誤訊息**
使用方法:
index(n)代表在容器的最大範圍內找第一個出現n的index值
index(n,a,b)代表在容器的index為a到index為b的範圍(不含b)找第一個出現n的index值
**count()**
回傳值在list內出現的次數
使用方法:
count(n)代表找n在tuple出現的次數
**sort()**
將list排序,數字依大小排序(從小到大),字串依字母前後順序及長度排序
此外,當list內部不是只有一個種類的物件(如有字串和數字同時存在),無法使用排序,只會發生錯誤
使用方法():
sort()
**reverse()**
將list順序完全倒過來
使用方法:
reverse()
範例
```
a=[]
a.append(40)
a.append(20)
print(a)
b=a.copy()
print(b)
a.extend(b)
print(a)
a.clear()
print(a)
b.insert(-1,54)
print(b)
b.reverse()
print(b)
b.remove(54)
print(b)
c=b.pop()
print(b)
print(c)
```
輸出結果:
```
[40, 20] #a
[40, 20] #b
[40, 20, 40, 20] #a
[] #a
[40, 54, 20] #b
[20, 54, 40] #b
[20, 40] #b
[20] #b
40 #c
```
### **set集合**
特性:無序性,可以更改資料,類似數學概念的集合,內部成員資料不能重複
範例
```
a={5,7,8,8,5,'apple'}
print(a)
```
輸出結果(由於是無序性的,所以每次印出來的結果可能會不同):
```
{8, 'apple', 5, 7}
```
**set的方法(function)**
**add()**
將物件加入集合當中
使用方法:
add(n)代表將n加入集合當中
**clear()**
將集合清空,只留下殼
使用方法:
clear()
**copy()**
將集合複製一份,並回傳
使用方法:
copy()
**pop()**
將集合中隨意一個成員拋棄,並回傳
使用方法:
pop()
**remove()**
將指定元素從集合中移除,找不到該元素會跳錯誤訊息
使用方法:
remove(n)代表將n從集合移出
**discard()**
跟remove()一樣會將指定元素從集合移出,但找不到該元素時不會跳錯誤訊息
**difference(),intersection(),union()**
將原來的集合和另一個集合做(差集/交集/聯集)運算,並把結果回傳為一個新集合
使用方法:
difference(myset),intersection(myset),union(myset)代表將使用這個方法的set與myset做(差集/交集/聯集)運算,並將結果回傳
**difference_update(),intersection_update(),update()**
將原來的(呼叫這個方法的)集合和另一個集合做(差集/交集/聯集)運算,並把結果覆蓋到原來的集合
使用方法:
difference_update(myset),intersection_update(myset),update(myset)代表將使用這個方法的set與myset做(差集/交集/聯集)運算,並將結果覆蓋到呼叫方法的set
**issubset()**
判斷呼叫的集合是否為指定集合的子集合,回傳真假值(bool)
使用方法:
issubset(myset)代表判斷呼叫的集合是否為myset的子集合
**isuperset()**
判斷指定的集合是否為呼叫的集合的子集合,回傳真假值(bool)
使用方法:
issubset(myset)代表判斷myset是否為呼叫的集合的子集合
範例:
```
a={10}
a.add(20)
a.add(80)
a.add(40)
a.add(20)
print(a)
b=a.copy()
print(b)
c=b.pop()
print(c)
print(b)
if b.issubset(a):
print('TRUE')
else:
print('False')
d={60,20}
a.intersection_update(d)
print(a)
f=b.intersection(d)
print(f)
```
輸出結果:(由於使用了pop(),輸出結果可能會不同)
```
{80, 10, 40, 20} #a
{80, 10, 40, 20} #b
80 #c
{10, 40, 20} #b
TRUE
{20} #a
{20} #f
```
### dict字典
特性:無順序性(3.6版開始有順序性),有特別對應關西(一個key對上一個value),key之間不能重複,value則沒此限制,可以更改內容,此外key的型態不能為list或dict(因為兩者為unhashable)
宣告範例(四種建立方法)
```
a={1:42,(4,2):[30,74],5:'apple'}
print(a[(4,2)])
b=dict({2:'a','6':2})
print(b['6'])
c=dict([[10,6],['apple','orange']])
print(c['apple'])
d=dict(zip((1,2),(3,8))) #1是3的key 2是8的key
print(d[2])
```
輸出結果:
```
[30, 74]
2
orange
8
```
**dict的方法(function)**
**新增(修改)組合的方法**
容器名稱[想增加(修改)的key]=想增加(修改的value)
**setdefault()**
尋找指定key值,並回傳對應的value,若該key值不存在,則建立此key值,value預設為None(或自訂的值)
使用方法:
setdefault(n)代表尋找並回傳n所對應的value,若找不到則建立,其對應的value則為None
setdafault(n,'apple')代表尋找並回傳n所對應的value,若找不到則建立,其對應的value則為'apple'
**get()**
放入key值能,回傳對應value,與dict[]不同的是,當key值不存在,會回傳None(或是自訂回傳的物件),而非錯誤訊息
使用方法:
get('a')代表回傳'a'為key值所對應的value
get(n,10)代表回傳n為key值所對應的value,若沒有此key值,就回傳10
**clear()**
清空呼叫方法的dict內部,留下殼
使用方法:
dict()
**items()**
回傳一個二維list,內部為呼叫方法的dict的key以及對應的value值
使用方法:
items()
**keys()**
回傳一個list,內部為呼叫方法的dict的所有key值
使用方法:
keys()
**values()**
回傳一個list,內部為呼叫方法的dict的所有values值
使用方法:
values()
**pop()**
移除指定key值和所對應value,回傳該value值,若key值不存在,則跳出錯誤(或自訂的物件)
使用方法:
pop(n)代表刪除n為key值和對應的value的組合
pop(n,'d')代表刪除n為key值和對應的value的組合,若n不在就回傳'd'
**popitem()**
移除最晚被加入的組合(key-value),並回傳這個組合(tuple型態),若dict已空,則回傳錯誤訊息
使用方法:
popitem()
**update()**
將另一個dict的所有內容(key-value),加到呼叫方法的dict,若有重複的key值,則把另一個dict的value覆蓋上去
使用方法:
update(mydict)代表將mydict的所有內容放入呼叫的dict內部
範例:
```
d={1:2}
d.setdefault(1,20)
d.setdefault(9,'b')
print(d)
d['66']=77
print(d)
print(d.get(3,'Not Found'))
print(d.get(9))
list1=d.items()
print(list1)
print(d.keys())
print(d.values())
k={1:11,4:'b'}
d.update(k)
print(d)
```
輸出結果:
```
{1: 2, 9: 'b'} #d
{1: 2, 9: 'b', '66': 77} #d
Not Found
b
dict_items([(1, 2), (9, 'b'), ('66', 77)])
dict_keys([1, 9, '66'])
dict_values([2, 'b', 77])
{1: 11, 9: 'b', '66': 77, 4: 'b'} #d
```
## <p id="string">字串處理</p>
### 字串
可以用' '," ",''' '''去宣告一個字串
可以說是字元的容器,把字元裝在一起,並且允許使用[index]去存取,也能使用+去增加字串,但加入後不能修改內容
index為0,代表取index為0的位置(也是字串的第一位)的字元,若index為負,則代表從後面數來的第幾個,-1即代表倒數第一個
範例
```
str='abc'
print(str[0],str[1],str[2],sep='->')
print(str[-1],str[-2],str[-3],sep='->')
```
輸出結果:
```
a->b->c
c->b->a
```
### 字串加和乘
可以透過+來讓兩個字串聯接,也可以透過*讓字串重複
範例
```
s1=' abc '
s2=' qwe '
s3=s1+s2
print(s3)
s4=s1*2+' ; '+s2*3
print(s4)
```
輸出結果:
```
abc qwe
abc abc ; qwe qwe qwe
```
### 進階中括號[]使用方法:
[X:Y:Z]
XYZ都必須為整數
X代表開始的index值,預設為0
Y代表結束的index值,預設為len(使用的字串),即字串長度,此外不會走到Y的位置
Z代表一次走多少位置,預設為1
走一次即從X開始最多走到Y-1的index位置,然後每次走Z個位置
範例
```
s='abcde'
print(s[1:3:1])
print(s[0:4:2])
print(s[-1:0:-1])
print(s[1::2])
print(s[:2:])
```
輸出結果:
```
bc
ac
edcb
bd
ab
```
---
### String字串的常用方法(function)
只要變數是字串型態,都能呼叫這些方法
### 字串變換(回傳新字串)
**strip()從兩邊,lstrip()從左邊,rstrip()從右邊**
將字串將從最左或最右(往中間)清除指定的字元,直到不是要清除的字元為止,預設為清除空白,並回傳為一個新字串(原字串不會改變)
使用方法:
strip()清除呼叫字串的最左邊最右邊,並回傳一個新的字串
strip('ab')清除呼叫字串的從最左邊和最右邊開始遇到的字元a和b,直到不是這兩個字元('ab'可以以一個字串變數代替)
範例
```
s=' bBbaadBBb'
s1=s.strip()
print(s1)
s2=s.strip('b ')
print(s2)
s3=s.lstrip('b')
print(s3)
s4=s.rstrip('b')
print(s4)
print(s)
```
輸出結果:
```
bBbaadBBb #從兩邊清除空白
BbaadBB #從兩邊清除空白和b
bBbaadBBb #從左邊清除b
bBbaadBB #從右邊清除b
bBbaadBBb #s不會被改變
```
**swapcase()**
將字串變成大寫英文字母換成小寫,小寫英文字母換成大寫,並回傳為一個新字串
使用方法:
swapcase()
範例
```
s=' MOusE '
print(s.swapcase())
```
輸出結果:
```
moUSe
```
**capitalize()**
將第一個字母(必須放在字串最前面,即index為0的位置)轉換成大寫,其餘字母全轉成小寫,並回傳為一個新字串
使用方法:
capitalize()
範例
```
s='MOUSE'
print(s.capitalize())
s=' MOUSE'
print(s.capitalize())
```
輸出結果:
```
Mouse
mouse
```
**title()**
將字串轉換為類似英文報紙或作品標題格式,即每個單字(中間有空格隔開)的第一個字母大寫,且其餘字母變成小寫,並回傳為一個新字串
使用方法:
title()
範例
```
s='hello wORLD!! THIS is Lancaster sPEaking'
print(s.title())
```
輸出結果:
```
Hello World!! This Is Lancaster Speaking
```
**upper(),lower()**
將字串全部英文字母改為大寫(小寫),並回傳為一個新字串
使用方法:
upper()
lower()
**zfill()**
放入指定長度,若長度大於原字串,將從字串左邊補上0,直到符合長度,否則不會有任何改變,並回傳為一個新字串
使用方法:
zfill(n),若呼叫的字串長度小於n,把字串左邊補上0,直到長度為n,並回傳為新字串
範例
```
s='aaa'
print(s.zfill(1))
print(s.zfill(len(s)+4))
```
輸出結果:
```
aaa
0000aaa
```
### 字串判斷(回傳bool真假值)
**startswith(),endswith()**
檢查字串指定範圍內是否以指定字串為開頭(結尾),回傳一個真假值(bool),若沒打範圍,則預設為整個字串
使用方法:
startswith('abc')檢查呼叫的字串是否為以abc為最前面三個字元
startswith('abc',2,7)檢查呼叫字串的index 2到index 6(不含7)是否以abc為前三個字元(即檢查index2是否為a index3是否為b index4是否為c)
endswith('abc')檢查呼叫的字串是否以abc為最後三個字元
endswith('abc',5,14)檢查呼叫字串的index 5到index 13(不含14)是否以abc為最後三個字元(即檢查index11是否為a index12是否為b index13是否為c)
範例
```
s='this is my pens'
print(s.startswith('this'))
print(s.startswith('this',5,10))
print(s.endswith('pen'))
print(s.endswith('s',0,4))
```
輸出結果"
```
True
False
False
True
```
**istitle()**
判斷字串內部是否每個單字的第一個字都是大寫,且其餘字母為小寫,回傳真假值(bool)
(可用來判斷這個字串是否被title()過)
使用方法:
istitle()
範例
```
s='this Is my Pens'
print(s.istitle())
s='THIS Is My PENS'
print(s.istitle())
s='This Is My Pens'
print(s.istitle())
```
輸出結果:
```
False
False
True
```
**isupper(),islower()**
判斷所有字母是否都為大寫(小寫),回傳真假值(bool)
(可用來判斷字串是否被upper()或lower()過)
使用方法:
isupper()
範例
```
s='hello wORLD!!'
print(s.upper().isupper()) #會先變成upper()過的新字串,再呼叫isupper()的方法
```
輸出結果:
```
True
```
**isalnum()**
判斷呼叫的字串裡面是否只含a~z和A~Z和0~9這些字元,若是多行字串裡面必有'\n'(換行字元),因此必為false,回傳真假值(bool)
使用方法:
isalnum()
範例
```
s='hello AZ123'
print(s.isalnum())
s='helloAZ123'
print(s.isalnum())
```
輸出結果:
```
False #空格不屬於該範圍,所以為false
True
```
**isalpha()**
判斷呼叫的字串裡面是否只有英文字母,回傳真假值(bool)
使用方法:
isalpha()
範例:
```
s='aa bb'
print(s.isalnum())
s='aabb'
print(s.isalpha())
```
輸出結果:
```
False
True
```
**isdigit()**
判斷呼叫的字串是否為數字,回傳bool值
可以搭配eval()使用,先判斷字串是否為數字,在在使用eval()轉成數字型態,這樣可以避免eval()產生錯誤
使用方法:
isdigit()
範例:
```
s='731'
if(s.isdigit()):
x=eval(s)
print(x)
else:
print('該字串不是數字')
```
輸出結果:
```
731
```
**isspace()**
判斷呼叫的字串裡面的所有字元是否為只有空白字元的字串
使用方式:
isspace()
範例:
```
s=' '
print(s.isspace())
s=' 4 '
print(s.isspace())
```
輸出結果:
```
True
False
```
### 字串切割及尋找
**split()**
將字串根據條件切成多個小字串,回傳list,裡面為切割好的小字串,小字串至少會有一個字元存在
可以使用的傳入參數有兩個:
* sep可以設定遇到怎樣的字元或字串要切割,若沒設定,則預設為單個空白
* maxsplit可以設定回傳的list最多使用到第幾個index值,代表可以限制切割的小字串數量,若沒設定,則預設為切到字尾(設為1代表最多只能使用到index為1,即代表只有兩個小字串)(maxsplit的值+1即為結果的小字串數量)
使用方式:
split()代表遇到空白就會切,且切到字尾為止
split(sep='a')代表遇到a就會切割字元,且切到字尾為止,此外也可以直接打成split('a')
split(sep='man',maxsplit=3)代表遇到man就會切割字元,且最多只能使用到index為3個位置,即只會有4個小字串(index0~3),此外也可以直接打成split('man',3)
範例
```
s1='I am iron I am man!'
s2=''
list1=s1.split()
for str in list1:
print(str)
s2+=str
print(s2)
list2=s1.split(sep='am',maxsplit=1)
print(list2)
```
輸出結果:
```
I
am
iron
I
am
man!
IamironIamman! #將且割完的小字串接到一起
['I ', ' iron I
```
**splitlines()**
將多行的字串切成一行一行的並回傳一個list裡面為每一行的字串
使用方法:
splitlines()
範例
```
s='abc abd \n afff \n dadad '
print(s.splitlines())
```
輸出結果:
```
['abc abd ', ' afff ', ' dadad ']
```
**partition()**
將字串根據指定字元或字串切割成三部分,並回傳為空間為3的tuple,且只會切第一個符合的,若找不到則回傳的tuple的index0為原字串,而後面兩個位置為''(空字串),此外與split()不同的地方,除了一定只切一次,還有會保留指定的字元或字串
使用方法:
partition('bad')代表遇到bad就切為三部分
範例
```
s='an apple is here'
t=s.partition('b')
print(t)
t=s.partition('is')
print(t[0],t[1],t[2],sep='\n')
```
輸出結果
```
('an apple is here', '', '')
an apple
is
here
```
**count()**
尋找指定字元或字串在呼叫的字串裡面出現幾次,並回傳為一個整數
此外能設定搜尋的範圍index,預設的範圍就是全部字串
使用方法:
count('qq')代表從頭開始尋找qq直到最後,並回傳找的次數
count('apple',5)代表從index5開始尋找apple直到最後,並回傳找的次數
count('b',1,8)代表從index1搜尋到index7(8-1)尋找b,並回傳找的次數
範例
```
s='abc abd acd bca ba'
print(s.count('ab'))
print(s.count('a',5))
print(s.count('a',5,8))
```
輸出結果:
```
2
3
0
```
**find(),index()**
尋找指定字元或字串第一次出現的index值(字串的情況就傳第一個字元出現的index位置),跟count()一樣也能設定範圍,且規則一樣
這兩個方法不同的地方在於find()找不到的時候是回傳-1,而index()則是回傳一個錯誤的訊息
使用方法:
find('a')代表找從頭到尾找第一個出現a的index值,找到就回傳,否則回傳-1
find('b',6)代表從index6找到最後,找到就回傳,否則回傳-1
find('ple',2,15)代表從index2找到index14(15-1),找到就回傳該位置裡面p的index值,否則回傳-1
範例
```
s='abc abd acd bca ba'
print(s.find('ab'))
print(s.find('ab',2))
print(s.index('ab'))
print(s.index('ab',2))
print(s.find('a',5,8))
```
輸出結果:
```
0
4
0
4
-1
```
---
## <p id="function">函數</p>
除了物件本身可以呼叫的函數(方法),我們也可以自訂函數,而好處就在於可以讓特定功能重複被使用,每次要使用時,只要呼叫函數就行,此外要注意的是,必須先定義函數才能呼叫,所以函數定義最好寫在程式碼前部分
函數的可以分為四部份:
* 回傳值:呼叫函數完後要回傳的變數或值,可以用逗號來回傳多個,也可以不回傳值,但會變成自動回傳None物件
* 函數定義:函數的內容,且要縮排,函數內部新宣告的變數都是區域變數
* 參數:呼叫函式時,要使用的變數,也可以不傳入任何參數,有順序性,屬於區域變數,傳入時,會依 照順序,否則必須打上參數名稱
* 函數名稱:用來呼叫函數
<p><b>當傳入參數太多時,為避免要命名很多參數名稱,可以使用*將眾多變數放在同一個tuple或使用**將其放在同一個dict</b>,使用方法即是在參數前面打上*或**</p>
**return的功用**
return除了可以回傳值,還有跳離函數的功用,代表只要在函數中執行return,函數就會直接回到呼叫的地方,而不管函數是否執行完,所以只要函數已經執行到我們想要的部分完就能使用return了,就如同迴圈中的break,此外也可以不使用任何return,如同迴圈沒有break,這樣只要函數全部執行完,就會回到呼叫的地方
自訂函式的方法:
```
def 函數名稱(參數名稱,參數名稱...):
函數內容
...
return 要回傳的物件1,要回傳的物件2..
```
範例(先定義好myfunction再呼叫)
```
def myfunction(a,b): #a和b即為參數
c=a+b
d=a*2+b*2
return c,d #c和d為回傳值
num1=10
num2=20
print(myfunction(num1,num2)) #num1和num2為引數,沒打上參數名稱,照順序給參數
s1='apple'
s2='cat'
print(myfunction(b=s1,a=s2)) #s1和s2為引數,並打上參數名稱
```
輸出結果:
```
(30, 60)
('catapple', 'catcatappleapple')
```
範例(return可以有多個,且沒回傳值時,會回傳None,此外在這個範例中,最後的return可以省略)
```
def myfunction(a,b):
a=a+b
if a>10:
return True
return
print(myfunction(5,8))
print(myfunction(4,2))
```
輸出結果:
```
True
None
```
範例(將多個參數變成一個tuple或dict)
```
def myfunction1(*a):
ans=0
for num in a:
ans+=num
return ans
def myfunction2(**a):
for element in a:
print('%s\'s score:%d'%(element,a[element]))
print(myfunction1(46,34,87,63,10,28,92))
myfunction2(Mary=52,Ken=84,cindy=90,Leo=40)
```
輸出結果
```
360
Mary's score:52
Ken's score:84
cindy's score:90
Leo's score:40
```
### 參數vs引數
**參數**是在函數括號內部的區域變數,且當函數結束就會消失,且不能再函數外使用的變數。
**引數**則是呼叫函數時,給函數當作內部參數要複製值的對象
所以當參數值改變不會影響引數的值,但如果參數的型態為容器,則會影響同為容器型態的引數
### pass by reference傳址(傳參考) vs pass by value傳值
在參數引數之間的關係可以分為這兩種
傳址:把引數的記憶體位置傳給參數,參數改變會影響引數,當參數是容器才會使用傳址
傳值:把引數的值複製給參數,而使用不同記憶體空間,參數一般都是傳值
範例
```
def myfunction(a,b):
a[0]=500000
b=100
list1=[50]
num=20
myfunction(list1,num)
print(list1,num)
```
輸出結果:
```
[500000] 20
```
### 預設參數
要是參數沒有得到可以複製值得對象的情況,我們可以令它為一個預設的值來避免錯誤,若變數沒有預設的值,就代表呼叫的時候必須給它引數,此外在宣告的括號裡面,有預設值的參數數要在沒預設值的參數後面
```
def 函數名稱(參數名稱,參數名稱=預設的值...):
函數內容
...
return 要回傳的物件1,要回傳的物件2...
```
範例
```
def myfunction(a=30,b=2):
return a/b
num1=10
num2=20
print(myfunction())
print(myfunction(num1))
print(myfunction(num1,num2))
```
輸出結果:
```
15.0
5.0
0.5
```
### 全域變數在函數中和global
在自訂函數中若沒有變數名稱與全域函數名稱相同,可以存取全域變數的值,但不能修改,除非先加入global定義全域變數
使用方法:
global 全域變數名稱
此外若該全域變數不存在,這樣就等於直接在自訂函數中宣告了一個全域變數,但如果這個函數沒被呼叫,那也是沒宣告到
範例
```
a=1
def func1():
global a
a = 99
def func2():
global b
b=31
func1()
func2()
print(a,b)
```
輸出結果:
```
99 31
```
---
## <P id = 'mod'>模組</P>
模組是一種.py檔,用來保存程式碼,好處在於可以把常用的函數或是類別甚至是變數保存起來,隨時引入即可使用。
### 引入模組
要先引入想使用的模組才能使用其內部程式
**引入方法1**(整個引入):
```
import 模組名稱1,模組名稱2...
```
**引入方法2**(部分引入,只引入某部分程式碼):
```
from 模組名稱 import (類別/函數/變數)名稱1,名稱2...
```
方法2引入的東西不需要模組名就能直接呼叫
**引入方法3**(將所有引入,但也可以不用模組名就能呼叫)
```
from 模組名稱 import *
```
**注意**
雖然方法2和方法3使用起來比較方便,但是若原程式有同的名稱的東西可能會造成被覆蓋,所以得僅慎使用
範例
```
import time
from math import pi,sqrt
print(pi,sqrt(25)) #使用方法2因此不用模組名就能使用
print(time.gmtime()) #使用方法1因此要模組名才能呼叫
```
輸出結果:
```
3.141592653589793 5.0
time.struct_time(tm_year=2021, tm_mon=7, tm_mday=16, tm_hour=6, tm_min=47, tm_sec=29, tm_wday=4, tm_yday=197, tm_isdst=0)
```
此外模組的py檔必須在sys.path裡面,sys.path有好幾條路徑,他會依序尋找
可以透過執行下面程式知道sys.path
```
import sys
print(sys.path)
```
**as**
要呼叫模組的東西必須先打上模組名稱.要呼叫的東西,若模組名太長會比較麻煩,因此在import時,可以用as使模組名被取代,這樣可以避免模組名太長,甚至把模組名改成方便使用的,但不會真的更改模組實際名稱,只會影響這支程式(import模組的程式)裡面的模組名稱,此外使用as後就不能使用原模組名稱
```
import 原模組名稱 as 想要的模組名稱
```
### 常用官方模組
官方標準的模組通常都跟python一起裝好了,所以直接import就可以使用
下面列舉幾個常用模組和裡面常用函數
此外除了官方,也有其他人開發的模組(第三方模組)可以使用,但必須額外安裝
#### **time** [官方說明網頁](https://docs.python.org/3/library/time.html?highlight=time#module-time)
**time.sleep(秒數)**
可以使程式暫停幾秒
**time.localtime()**
回傳本地時間
**time.gmtime()**
回傳UTC世界標準時間
---
#### **random** [官方說明網頁](https://docs.python.org/3/library/random.html)
產生亂數的模組,但不適合用來產生密碼
**random.randint(最小值,最大值)**
回傳一個隨機整數,**大於等於**最小值且**小於等於**最大值
**random.randrange(值1,值2,差)**
回傳一個隨機整數,介於值1和值2,但永遠不會為值2,當差>0 值2要大於值1,當差<0,值2要小於值1,此外差必須為整數,差影響的是亂數產生的間距
亂數產生的公式
亂數=值1+整數隨機亂數*差
範例
```
import random
print(random.randrange(2,8,3)) #可能產生的數:2 5 2=2+0*3 5=2+1*3
print(random.randrange(6,-2,-3)) #可能產生的數:6 3 0 6=6+0*(-3) 3=6+1*(-3) 0=6+2*(-3)
```
輸出結果:
```
5
3
```
**random.random()**
回傳一個**大於等於**0且**小於**1的隨機浮點數
**random.uniform(最小值,最大值)**
回傳一個**大於等於**最小值且**小於等於**最大值的隨機浮點數
**random.choice(容器或字串)**
從有順序性的容器(list,tuple,range)或字串隨機選出一個成員
範例
```
import random
a='afqwert'
b=(1,'saa',78)
c=[4,2,'pe']
print(random.choice(a))
print(random.choice(b))
print(random.choice(c))
```
輸出結果
```
r
1
pe
```
**random.sample(容器或字串,隨機的不重複的數量)**
從有順序性的容器(list,tuple,range)或字串隨機選出指定數量且不重複的成員,跟排列組合裡面的C一樣,並回傳為一個list
範例
```
import random
a='afqwert'
b=(1,'saa',78,99)
c=[4,2,'pe']
print(random.sample(a,2))
print(random.sample(b,3))
print(random.sample(c,2))
```
輸出結果:
```
['a', 'f']
[1, 99, 'saa']
[2, 4]
```
**random.shuffle()**
將list裡面的順序重新隨機洗牌,會直接改變list的順序,不回傳任何值
範例
```
import random
c=[4,2,'pe','kk','gg',74]
random.shuffle(c)
print(c)
```
輸出結果:
```
[74, 4, 2, 'pe', 'gg', 'kk']
```
---
#### **os** [官方說明網頁](https://docs.python.org/3/library/os.html?highlight=os#module-os)
有一些系統上的操作指令函數
注意以下路徑或檔案名稱都是用字串型態傳入
此外這邊的檔案路徑可分為絕對路徑和相對路徑
**絕對路徑**就是從完整的路徑,但是必須把/改成//來辨識為絕對路徑,例如C:\\Users\\User\\Desktop\\python\\hello.txt
**相對路徑**就是依照os.getcwd()得知當前的目錄,再以這個為基礎去給相對的路徑,假如當前路徑是:C:\\Users\\User\\Desktop,那hello.txt的相對路徑,就會是\pyhton\hello.txt
**..\\** 在相對路徑中可以達到回上一層的功能
**os.getcwd()**
回傳當前目錄位置
**os.chdir(路徑)**
切換當前目錄到該路徑下
**os.rename(目標,新名稱)**
對目標檔案或資料夾改名
**os.remove(檔案路徑)**
專門用於刪除檔案
**os.removedirs(資料夾路徑),os.rmdir(資料夾路徑)**
專門用於刪除**空的**資料夾,不是空的不能刪除
**os.listdir(路徑)**
列出路徑下的所有資料夾和檔案
**os.mkdir(路徑)**
建立新的資料夾,路徑不打就是在當前目錄建立新資料夾
**os.path.getsize(路徑)**
回傳檔案大小
**os.path.getctime(路徑)**
回傳檔案建立的日期
**os.path.getmtime(路徑)**
回傳檔案修改的日期
**os.path.getㄇtime(路徑)**
回傳檔案存取的日期
**os.path.isfile(路徑)**
檢查路徑是否為一個檔案,回傳真假值
**os.path.isdir(路徑)**
檢查路徑是否為一個資料夾,回傳真假值
**os.path.exists(路徑)**
檢查路徑的資料夾或檔案是否存在,回傳真假值
**os.system('...')**
可以開啟命令提示字元並執行''裡面打的命令
### 自訂模組
可以編寫自己的模組,來作為常用的工具,此外,在自訂模組中,也可以引入其他模組來使用
範例
mylib.py(自己編寫的程式,計算園面積,以及使用餘弦定理計算第三邊)
```
import math
pi=3.1415926 #其實math裡面就有標準的pi了
def area(r):
return r*r*pi
def getTheThird(b,c,degree):
return math.sqrt(b*b+c*c-2*b*c*math.cos(degree*math.pi/180))
```
test.py
```
import mylib as m
print(m.area(5))
print(m.getTheThird(3,4,90))
```
輸出結果:
```
78.539815
5.0
```
---
## <p id = "file">檔案處理</p>
檔案處理的好處在於。可以將資料放在其他檔案中,而不用預先寫進程式碼,或是將程式執行結果寫進一個檔案中保存,此外這裡的檔案是**txt檔**
### 檔案處理的步驟一 開檔
開檔的目的在於先知道目標的檔案,才能在做第二步驟的存取
**開檔方式**為使用一個變數去當作接收open()回傳的檔案物件
```
變數名稱 = open(檔案路徑,存取模式,資料讀入的暫存空間)
```
**檔案路徑**
可以用相對路徑或絕對路徑(在官方模組os的說明有解釋過了,可以往上找尋),此外檔案的副檔名.txt也要有
**存取模式**
讀取模式可決定你可以對檔案做出怎樣的操作,此外傳入此參數時候要用字串型態,若不打則預設為r
* r 以唯讀模式開啟檔案並**從頭**開始讀取,不能對檔案作和和更改,
* r+ 以同時能讀和寫模式開啟檔案並**從頭**開始,可能會覆蓋原有的資料
* w 以寫入模式開啟檔案並**從頭**開始寫入,會覆蓋原有的資料
* w+ 以同時能讀和寫模式開啟檔案並**從頭**開始,可能會覆蓋原有的資料
* a 以寫入模式開啟檔案並從**最後**開始寫入,因此不會覆蓋到原有資料
* a+ 以同時能讀和寫模式開啟檔案並從**最後**開始
**w+和r+的不同**,w+會將檔案完全的清空覆蓋上新的資料(即使沒做步驟二的任何操作),r+不會將檔案清空,會依照新的資料若用到舊的位置,才覆蓋上去
當檔案不存在時,r/r+會傳錯誤訊息,而w/w+/a/a+則會建立新檔案
如果是在讀二進位檔案必須在讀取模式的字後面加b,例如rb,a+,wb+...等
**資料讀入的暫存空間**
以數字方式傳入,功用為決定一次能讀取的資料行量,0代表沒有暫存空間,-1代表使用預設的暫存空間,其他數字則能代表為一次能讀幾行的暫存空間,**通常可以不打這個參數**,讓它使用預設的就好
### 檔案處理的步驟二 寫檔或讀檔
根據步驟一的存取模式決定是寫檔或讀檔,此外需要注意檔案的游標位置,會決定讀取或寫入的東西,游標過了的地方就不會被影響了
#### **讀檔**
將檔案內容讀進來,此外要注意的是,可以混和使用,但是讀過的地方就不會再讀了因為游標已經過去了
使用方法:**檔案的變數物件.函數**
read()
將檔案全部內容讀進,並回傳為一個字串
readline()
將檔案讀一行,並回傳為一個字串
readlines()
將檔案一行一行讀成一個字串直到讀完,並回傳為一個list,內部每個index為每一行
範例
data.txt
```
hello world!!
today
monster
```
程式碼
```
f=open('data.txt','r')
result=f.read()
print(result)
f.close()
f=open('data.txt','r')
print(f.readline())
print(f.readlines())
f.close()
```
輸出結果:
```
hello world!!
today
monster
hello world!!
['today\n', 'monster']
```
#### **寫檔**
將資料寫入檔案
使用方法:**檔案的變數物件.函數**
write()
將字串型態的資料寫入檔案(只能傳入字串),不會自動換行
writelines()
將內部全部都是字串的list寫入檔案(只能傳入list),不會自動換行,每個字串會直接連載一起,想換行必須在自己加'\n'
範例
data.txt
```
hello world!!
today
monster
```
程式碼
```
f=open('data.txt','r+')
lst=['apple','bad\n']
f.write('pppppp')
f.writelines(lst)
f.close()
```
輸出結果:
data.txt
```
ppppppapplebad
oday
monster
```
### 檔案處理的步驟三 關檔
當結束存取後,必須要關檔,這樣才能保存存入的資訊,或是避免檔案被鎖定,不能被更動的下場
關檔方式
```
檔案物件變數.close()
```
---
## <p id="exception">例外處理</p>
當程式發生錯誤就會跳出對應的錯誤訊息並且中止程式,例外處理可以讓錯誤發生時,不中止程式,並可以做出適當的處理
例外處理方法
當程式碼發生錯誤就會往下找到第一個符合的例外情況
else和finally可以省略
```
try:
程式碼(可能產生錯誤的程式碼)
...
except 例外情況1(可能發生的錯誤訊息):
當符合這個例外情況1要執行的程式碼
...
except 例外情況2(可能發生的錯誤訊息):
當符合這個例外情況2要執行的程式碼
...
else:
當程式沒有發生任何錯誤,要執行程式碼
...
finally:
當上面全部都執行完,都會要執行的程式碼
...
```
範例
```
try:
int('aphd')
except ValueError:
print('無法轉換為數字')
else:
print('轉換成功')
finally:
print('程式執行完畢')
try:
int('412')
except ValueError:
print('無法轉換為數字')
else:
print('轉換成功')
finally:
print('程式執行完畢')
```
輸出結果:
```
無法轉換為數字
程式執行完畢
轉換成功
程式執行完畢
```
### 得知錯誤訊息
可以藉由故意犯錯來知道錯誤訊息
例如
開檔未找到的錯誤
![](https://i.imgur.com/DA6XTlJ.png)
得知當檔案無法找到會跳出FileNotFoundError
---
## <p id="class">類別(class)</p>
在python裡面所有東西都是物件,但物件和物件之間的不同是源自於類別,類別就是物件定義的地方(模板),物件則是類別被實例化的結果,如同狗如果是一種類別,那人養的哈士奇,臘腸狗,柯基都是物件。
類別是定義物件的地方,因此有兩個地方可以被定義,一個是類別的屬性變數,一個是類別的函數,當一個物件被實例化後就能使用這些已經在類別被定義好的東西
### 建構式
建構式是只有當物件被建立時回呼叫的函數,可以用來初始化物件的變數或是做一些函數的呼叫。
使用方法為在類別中定義(繼承)__init__然後就能使用這個建構式,當類別的物件被創立就會自動呼叫它了,還可以決定傳入的參數
### 解構式
解構式是當物件沒被使用的時候(即已經沒有直接呼叫辦法可以使用此物件),會呼叫解構式並刪除物件
使用方法為在類別中定義(繼承)__del__然後就能使用這個解構式,當類別的物件被刪除就會自動呼叫它了
### 類別變數VS實體變數
在類別中類別變數是直接取名並使用的,而物件各自的變數(實體變數)是必須先加上self.變數名稱才能宣告,而且類別變數屬於都來自這個類別的物件,因此是共用的,而實體變數則是每個物件各自的變數
此外類別變數可以被同類別的物件使用或呼叫,但是若有實體變數和類別變數相同名稱,會優先呼叫為實體變數
### 在類別中自訂函數
如同一般的自訂變數的使用方法,不同的地方在於,傳入參數第一個必須是self,而且這個自訂變數只能被這個類別的物件呼叫使用
範例:
```
import random
class Robot:
centerX=0 #類別變數
centerY=0 #類別變數
def __init__(self,x,y): #建構式,並增加兩個傳入的參數x和y
self.x=x #建立兩個實體變數
self.y=y
def getLocation(self):
return[self.x,self.y]
def getCenter(self):
return(Robot.centerX,Robot.centerY)
def up(self,num):
self.y+=num
def down(self):
self.y-=1
def right(self,num):
self.x+=num
def left(self):
self.x-=1
def randomCenter(self): #隨機改變類別變數
Robot.centerX=random.randint(0,10)
Robot.centerY=random.randint(0,10)
robot1=Robot(9,7) #建立物件,傳入引數9,7給建構式的x和y
robot2=Robot(1,1) #建立物件,傳入引數1,1給建構式的x和y
robot1.up(4)
print(robot1.getLocation())
robot1.right(7)
print(robot1.getLocation())
for i in range(3):
robot1.down()
print(robot1.getLocation())
for i in range(1):
robot1.left()
print(robot1.getLocation())
print('center:',robot2.getCenter()) #用robot2呼叫函數印出類別變數
robot1.randomCenter() #用robot1打亂類別函數
print('center:',robot2.getCenter()) #用robot2呼叫函數印出類別函數,證明為共用
print('center:',robot2.centerX,robot2.centerY) #用物件名直接呼叫類別函數
```
輸出結果:
```
[9, 11]
[16, 11]
[16, 8]
[15, 8]
center: (0, 0)
center: (10, 9)
center: 10 9
```