# 小學PYTHON課程
## 課程分配
* 第一次
Python環境安裝,HackMD網路筆記本使用
我的第一支Python程式
變數的認識、for迴圈使用:九九乘法表
註解的使用
輸入與if判斷式:找出質因數
計算功能、運算子
* 第二次
資料型態與轉換、字串切割
串列List與資料切割
字典與資料切割
* 第三次
物件導向與import:簡易繪圖
簡易人臉辨識(依學生進度)
## 環境架設
* 用Anaconda當作開發環境,優點是整合了Package安裝、Environment建設及寫程式的環境
* 到官網下載 https://www.anaconda.com 最新版Anaconda安裝
* jupyter:寫phthon程式
* 點選執行
* 出現cmd視窗及網頁,若未自動執行網頁,在cmd視窗中複製網址到瀏覽器貼上執行
* 網頁會出現本機所有檔案,可以在這裡管理檔案、新增phthon程式,執行python程式
## 免費網路python程式資源
* Python3 https://www.youtube.com/watch?v=1PC3etgLwVc&list=PLXO45tsB95cIRP5gCi8AlYwQ1uFO2aQBw
* Python3 docs https://docs.python.org/zh-cn/3.7/library/index.html
* Solo Learn https://www.sololearn.com/Course/Python/
* Udemy https://www.udemy.com/pythonforbeginnersintro/
* Python https://happycoder.org/2016/12/31/python101-tutorial/
---
## 注意
* 英文大小寫不同
## 註解
``` Python
# 單行註解
"""
中間可以放
很多行的註解
"""
'''
中間可以放
很多行的註解
'''
```
## 計算
``` python
a ** c
# a的c次方
x = 9 % 5
#9除以5的餘數指定給x
x = 9 // 5
#將9除以5的整數部分指定給x,此範例x=1
```
* 計算的優先順序(以下方順序由上到下)
* ()
* 次方
* 乘法
* 除法
* 餘數%
* 整數//
* 加法
* 減法
* 指派運算子
```python
+= a+=b a=a+b
-= a-=b a=a-b
*= a*=b a=a*b
/= a/=b a=a/b
%= a%=b a=a%b
//= a//=b a=a/b 取整數的部分
**= a**=b a=a的b次方
```
## 變數
* 不需要事先宣告
* 名稱有大小寫之分
* 不可使用系統保留字或內建函數名稱,若使用了內建函數名稱當作變數,程式不會出錯,但是會讓原先的函數功能喪失
* 變數名稱內不可有, $ 以及不可由數字開頭
* 變數名稱可以用中文
* 刪除變數 ```del 變數名稱 ```
## 資料型態
* 先宣告變數,但未指定型態
``` python
var = None
# 代表尚未設定型態,此時用type(var),會顯示NoneType
```
* 布林:True False
``` python
x = 1
z = x == 1
執行後 z = True
```
### 字串:
* 變數名稱. 按tab鍵可以叫出快顯功能表(記得下參數)
* https://docs.python.org/3.4/library/string.html
* 逸出字元
* \\ = 反斜線
* \' = 單引號
* \" = 雙引號
* \a = 鈴聲
* \b = 倒退
* \f = 換頁
* \n = 換列
* \r = 游標移至最左邊
* \t = 水平跳格(TAB鍵效果)
* \v = 垂直定位
* \x = 16進位表示
* \N{id} = Unicode資料庫ID
* \uhhhh = Unicode 16位元之十六進位值
* \Uhhhh = Unicode 32位元之十六進位值
* \xhh = 十六進位值
* \o = 八進位表示
* \0 = null (是null字元,python不像C用null字元來判斷字串結束)
* 字串與整數相乘代表重複該字串的整數次數
* 字串前加上r可以取消字串中的逸出字元 ``` x = r'王小\n明' ```
* 把字串當串列用時,更改內容的串列函式不可用,其他的串列函示皆可套用,要想改變內容,就要將字串轉換成串列
``` python
y = "hello"
y = 'hello'
z = '''hello
word'''
z = """hello
word"""
#用三個引號包起來的方式可以換行,會加入\n這個字元
z[0]
#拿出第1個字母,把字串當串列用,但不能更改內容元素
z[-1]
#拿出最後1個字母
#-號代表從後面數過來
z.count
#變數後面加上 . 再按tab鍵,可以呼叫已經寫好的應用功能
y + z
#+將多個字串連起來
#另外可以用print("abc", "def", type(var))這種方式,每一個參數中會有一個空格
str()
#強制轉換為字串
chr()
#傳回數字參數的代表字元,用ASCII值,如chr(97)顯示a
ord()
#傳回字元參數的Unicode值,參數只能放1個字元
lower()
#轉換成小寫字
upper()
#轉成大寫字
title()
#轉成第一個字母大寫,其他是小寫
rstrip()
#刪除字串尾端多餘的空白
lstrip()
#刪除字串開始多餘的空白
strip()
#刪除字串頭尾兩端多餘的空白
nli = list('hello')
#將字串轉換成串列
split()
#將字串以空格為分隔符號,將字串內容拆成串列
```
### 數字
* 整數與浮點數會自動判斷
* 可以用2進位方式表示,0b開頭的表示2進位
``` python
bin() #轉換成2進位
```
* 可以用8進位方式表示,0o開頭的表示8進位
``` python
oct() #轉換成8進位
```
* 可以用8進位方式表示,0x開頭的表示8進位
``` python
hex() #轉換成8進位
```
``` python
int() #將資料型態強制轉換成整數,範例int(x)
float() #將資料型態強制轉換成浮點數
nb = list(range(3))
#nb = [0,1,2]
```
``` python
type()
#列出變數的型態
abs()
#計算絕對值
pow(x,y)
#返回x的y次方
round()
#進位,如果最左邊的數是奇數則使用四捨五入,如果是偶數則使用五捨六入,如round(1.5)=2 round(2.5)=2
round(5.364, 1)
#四捨五入進位到小數第1位
```
### 列表 串列 list
* 變數名稱. 按tab鍵可以叫出快顯功能表(記得下參數)
* 元素可以同時儲放不同型態的資料,或者另一個list
* 索引值-1代表最後一個元素,-2代表最後第2個元素
* 將兩個列表用+等於將兩個列表合併為一個列表,後面列表的元素就會接在前面列表元素的後面
* 串列內可以有字典元素
``` python
li = [1, 2, 3, 'stn']
liz = [1,2,3, [10,20,'str']]
li = li * 3
#將串列元素重複三次
li1 = li2 + li3
#將li2和li3串列合成一個li1的串列,也可以用 li2+=li3,
li = []
#宣告一個空的列表
li1 = li2
#將li1串列的位址拷貝給li2,所以更動li2時也會影響li1
li1 = li2[:]
#如果要拷貝內容而非位址用此方法,這樣兩個串列之間不會互相影響
li[0]
#拿出第1個值
li[3][2]
#取出多元串列得值
li[start:end]
#讀取從索引start到(end-1)索引的元素
li[0:4]
#從第0個開始拿四個值
li[:3]
#從頭取3個值
li[2:]
#從第3個值(因為開頭是0)取到最後
li[-3:]
#拿出後面三個值
li[:]
#取得所有元素
li[2:4:2]
#從第二個取到第四個,區間為2個
v1,v2,v3,v4=li
#將li的四個元素依序指定給v1 v2 v3 v4,這樣寫法較有效率
li[2] = 4
#修改第3個元素的值
del li[3]
#刪除li索引值3的元素
del li[2:4]
#也可以和[:]或[::step]的方法結合
del li
#刪除整個列表
#使用del刪除不會有回傳值,如果要回傳值,需使用pop()
vname = li.pop(2)
#參數是索引值,如果空白代表刪除最後一個元素
li.remove("car")
#刪除元素內容為car的
max(li)
#列表中的最大值,但有非數字元素會出錯
min(li)
#列表中的最小值,但有非數字元素會出錯
sum(li)
#列表中所有元素的總和,但有非數字元素會出錯
len(li)
#列表中有多少元素
li.append(111)
#把111接在li的最後一個元素
#參數也可以放另一個串列
li1.extend(li2)
#將li2的元素都併入li1中,變成一個串列,但是在anaconda中未實驗成功
li.insert(索引, 元素內容)
#插入新的元素,原有元素會向後排
li = li.astype(str)
#把li轉換成字串型態
pd.to_numeric(s, errors='coerce')
#轉換成數字,s是輸入項,errors= 'coerce'是指說轉換有誤,直接將值換成NaN,不要顯示出錯誤
li.reverse()
#反轉串列
li[::-1]
#將串列顛倒排序
li.sort()
#將串列由小到大排序,如果要從大到小,參數加上reverse=True
#排列英文時,建議先全改成大寫或小寫比較不會有錯
new_list = sorted(li)
#將li串列由小到大排序,並將結果指給new_list串列,原串列不動
#如果要從大到小,加上參數 sorted(li, reverse=True)
li.index("abc")
#abc在串列中第一次出現的索引值
li.count("abc")
#abc在串列中出現的次數
char.join(li)
#將li串列全部串再一起,char是串接的字元
#但是要注意格式,char是字串,但串列內的數字和文字無法直接合併
tuple(li)
#將list資料轉換成tuple
concat([序列1,序列2], axis = 1)
#將兩個序列合併,axis式合併方向,可以省略,預設是0,將序列2接在序列1的下方,如果是1,就是將序列2接在序列1的右方
#只能合併序列或DataFrame的資料
```
### enumerate
``` python
#將list tuple set等數值形式改用計數值與元素的方式傳回,傳回的數據稱為enumerate物件
#語法 obj = enumerate(iterable [,start = 0]),省略start設定,預設值是0
li1 = ["bask", "ask"]
li2 = enumerate(li1)
li2 = enumerate(li1, start = 10)
#將初始值設為10
for i,z in li2:
print(i,z)
```
### tuple 元組
* 與list串列相同,但是不可以更動元素值與元素個數
* 若要更新元素內容,需重新定義整個tuple
* 優點是資料更安全,也佔用較少的系統資源,增加執行速度
``` python
name_tuple = (元素1, 元素2, 元素3, ....)
#如果元素只有1個,要加上,
name_tuple = (元素1,)
#讀取元素(索引值從0開始)
name_tuple[2]
#讀取所有元素用
for i in name_tuple:
print(i)
#支援切片,方式跟list一樣
name_tuple[1:2]
#應用在list上面的方法如果不會更改元組內容都可以使用
list(name_tuple)
#將元組資料轉換成串列
max(name_tuple)
#獲得元組內容最大值
min(name_tuple)
#獲得元組內容最小值
#enumerate物件使用在元組
tuple(enumerate_name)
```
### 字典
* 也是串列型的資料,但是利用 鍵-值 的方式配對儲存
* 取用時也是用鍵key取值value
* 個別字典可以放近串列內,串列也可以放進字典內,字典內也可以放字典
``` python
# v = {key:value, key:valu,....}
score={'小民':90, '大徐': 80}
#或是
score={
'小民': 90,
'大徐': 80,
}
score = {}
#建立空字典
score['Keven'] = 95
#新增一筆字典到變數裏
print(score['大徐'])
#印出大徐的數字
len(score)
#字典累元素的數量
if keyname in score:
#檢查keyname(key值)是否在字典裡
for i,j in score.items():
#將字典內的鍵-值列一遍
#如果用for i,j in score: ,會將鍵拆成字,列出每個鍵的前兩個字
score.keys()
#資料所有的key
#範例 for i in score.keys():
#也可以用 for i in score :
score.values()
#資料所有的value
del score[鍵]
#刪除某個特定鍵元素
del score
#刪除整個字典
score.clear()
#刪除字典內所有元素,但字典還在,是個空串列
n_score = score.copy()
#將字典完整複製到n_score內
sorted(score.key())
#字典排序,依據鍵
score.fromkeys(list_name)
#使用串列list_name建立字典,串列內容會變成字典的鍵,如果沒有設定value值,則用none當值
score.fromkeys(list_name, 'abc')
#同上,但是設定每個值都是abc
score.get('abc')
#搜尋字典的鍵,如果鍵存在則傳回該鍵的值,如果不存在則傳回預設值
#如果沒有設定預設值則傳回none
#設定預設值的方式(預設值是defaultvalue)
score.get('abc', 'defaultvalue')
score.setdefault('abc')
score.setdefault('abc', 'defaultvalue')
#方法和get()相同,不同的地方是如果沒有這個鍵值,就會新增此元素
#沒有設定預設值則傳回none,有設定則依照設定\
score.pop(key[, default])
#依照key搜尋,找到就將該元素刪除,同時回傳刪除元素的值,如果沒有找到就傳回default的設定內容,如果沒有設定default則傳回keyError訊息
#建議還是設定default比較好
-----------------------------------------
範例
#將字典放進串列內,創出50個字典元素,並更改前3個字典的值
sold = []
for i in range(50):
solder={'tag':'red', 'speed':'slow', 'order':i}
sold.append(solder)
for solder in sold[:3]:
solder['tag'] = 'green'
print(sold[:5])
-----------------------------------------
```
### 集合 set
* 無序,每個元素都是唯一的(有重複時會刪除掉多的,只剩一個)
* 集合本身是可變的(可以增減元素),但是元素的內容是不可變的
* 整數、浮點數、字串、元組可當成元素,但是串列、字典、集合等不可以當成元素(會產生錯誤訊號),如果使用set()來建立集合,則可以放串列、字典、集合等元素,但是會將這些元素轉換成集合型元素
* 類別名稱是set
``` python
langs = {1,'abc',('g','h','i')}
langs = set()
#建立集合的方式,用第二種可以建立空集合
集合的操作
& 交集 intersection()
c = A & B
c = A.intersection(B)
| 聯集 union()
c = A | B
c = A.union(B)
- 差集 difference()
c = A - B
c = A.difference(B)
^ 對稱差集 symmetric_difference()
c = A ^ B
c = A.symmertic_difference(B)
== 等於
!= 不等於
in 是成員
not in 不是成員
A.add(元素)
#增加一個元素到集合內
A.clear()
#刪除集合所有元素,傳回值是none
A.copy()
#淺拷貝方式Shallow copy複製集合(改變一個集合內容時,另一個不會被改變)
A.difference_update(B[,C,....])
# 刪除A集合內與B集合(或B,C....集合)重複的元素,傳回值是None
A.intersection_update(B[,C,....])
# A集合改成B集合(或B,C....集合)的交集(沒交集的元素就刪除),傳回值是None
A.isdisjoint(B)
# 如果兩個集合沒有共同的元素則傳回True,否則傳回False
A.issubset(B)
# A集合是否是B集合的子集合(B集合的元素是否在A集合全部都有),傳回值是布林值
A.isupperset()
A.pop()
# 隨機刪除元素,所刪除的元素將被傳回,如果是空集合則傳回錯誤
A.discare()
# 刪除特定元素,如果沒有這個元素,也不會出現錯誤訊息
A.remove(元素)
# 刪除特定元素,如果沒有這個元素,會出現錯誤訊息
A.symmetric_difference_update(B)
# 刪除A集合內有A,B兩集合內都有的元素,並將B集合內沒有出現在A集合的元素加到A集合,和symmetric_difference()結果相同,只是被改變的集合不同
A.update(B[,C,....])
# 將B集合(或B,C....集合)的元素加到A集合中,傳回值是None
max(A)
#集合內的最大值,如果是字串,則列出unicode碼的最大值
min(A)
#集合內的最小值,如果是字串,則列出unicode碼的最小值
sum(A)
#集合內數值總和,不可用在字元或字串元素
len(A)
# 列出集合元素數量
sorted(A)
# 排序集合元素,並將結果存在新的串列物件內,原來的集合不會更動
enumerated(A)
# 傳回連續整數配對的enumerated物件
frozenset({'a','b','c'})
#凍結集合,凍結後就不可以再變了,不可以使用add或remove等指令,但可以執行 & | ^ 等集合查詢
-----------------------------------------
範例
langs = set('DeepBlue Mouton')
print(langs)
#結果顯示 {'D', ' ', 'p', 'e', 'M', 't', 'u', 'l', 'o', 'n', 'B'}
#字串被拆成字母,且重複的會刪除
li = ['apple', 'banana', 'orange', 'apple']
langs = set(li)
#也可以寫成 langs = set(['apple', 'banana', 'orange', 'apple'])
print(langs)
#結果顯示{'banana', 'apple', 'orange'},會刪除重複的
集合操作範例
A = {'a', 'b', 'c'}
B = {'c', 'd', 'e'}
A & B # {'c'}
A | B # {'a', 'b', 'd', 'c', 'e'}
A - B # {'a', 'b'}
B - A # {'d', 'e'}
A ^ B # {'d', 'e', 'a', 'b'}
A == B # False
A != B # True
'd' in A # False
'd' not in A # True
-----------------------------------------
```
### Hash 雜湊
* 一個物件在其生命週期內,如果保持不變,就是hashable
* 官方說法:如果一個物件在其生命週期內,其雜湊值Hash Value從未改變(這需要一個__hash__()方法),並且可以與其他物件進行比較(這需要一個__eq__()或__cmp__()方法),那麼這個物件就是可雜湊的。雜湊物件的相等意味著其雜湊值的相等。
* 雜湊性使得物件可以用作dictionary鍵和set成員,因為這些資料結構在內部使用了雜湊值。
* Python的所有不可變的內建物件都是可hashable的,但可變容器(如列表或字典)並非如此。對於使用者定義的類的例項,預設情況下是可雜湊的;它們都是不相等的,並且它們的雜湊值都是id()。
* list、set和dictionary 都是可改變的,比如list.append(),set.remove(),dict['key'] = value,是不可雜湊的;
* tuple和string是不可變的,只可以做複製或者切片等操作,這就是可雜湊的。
## 常用函式
``` python
# sum():算總和
# len():算長度
li = [1, 2, 3, 5]
alcount = sun(li)
allength = len(li)
help(print)
#列出print函數的說明
dir(__builtins__)
#列出所有內建函數
dir(物件名稱)
#列出適用本物件的內建函數
map(function, iterable)
#会根据提供的函数或指令對串列做映射
#參數1需使用處理用的函數,後面可以放多個迭代(如串列)
-----------------------------------------
範例
sq = list(map(lambda x: x ** 2, [1, 2, 3, 4, 5]))
print(sq)
#輸出[1, 4, 9, 16, 25]
sq = list(map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10]))
print(sq)
#輸出[3, 7, 11, 15, 19]
map(str,li)
#列如將串列內的所有元素都改成文字
-----------------------------------------
filter(function, iterable)
#過濾序列用
#參數1需使用判斷用的函數,參數2則需要可迭代對象,如串列
#返回值是一個列表,格式是filter
-----------------------------------------
範例
def is_odd(n):
return n % 2 == 1
#此時回傳True或False
newlist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
for i in newlist:
print(i)
#逐一印出奇數
-----------------------------------------
print()
#https://www.programiz.com/python-programming/methods/built-in/print
print("aa",var1,"bb",var2)
#將字串連再一起,,會在字串間產生一個空格
print("aa"+var1+"bb"+var2)
#將字串連再一起,,字串間無空格
print('%d %.2f %s' % (1, 99.3, 'Justin'))
#字串格式化輸出 print("輸出格式區"%(變數系列區,'''''')
#格式化輸出 %d 整數 %f浮點數 %x 16進位 %o 8進位 %s 字串
#%(+|-)m.nf 浮點數,m保留多少格數供輸出(含小數點),n保留多少格數空間
#%(+|-)nd %(+|-)no %(+|-)nx %(+|-)ns n是保留多少格數空間
#保留空間不足將完整輸出資料,如果保留個數空間太多,資料靠右對齊
#https://openhome.cc/Gossip/Python/StringFormat.html
print('%d %.2f %s' % (1, 99.3, 'Justin'),end = " ")
#跟上面一樣,但是結尾會增加end指定的字串,如果end寫成end='',就變成結尾不換行
print("{}資料內容{}資料內容{}以下推".format(var1,var2,var3))
#搭配format的用法
print("write to docs this word", file=fileObj)
#將文字列印到檔案
id()
#查看變數的位址
input()
#輸入資料,回傳一率是字串類型,要計算需要轉換成數字
name = input("請輸入姓名:")
in
not in
#判斷一個物件是否位於另一個物件內,物件可以是字串、串列、元組、字典等
# a in b ,回傳布林值
is
is not
#判斷兩個物件是否相同,物件可以是字串、串列、元組、字典等
#並不只是內容相同,而是指物件變數指向相同記憶體
pass
#跳過目前步驟,不作任何處理,也沒有任何輸出
replace("=", ">")
#取代,把 = 換成 >
apply()
#對DataFrame裡面的每一條Series都做同一動作,動作寫在()裏
print("abc","GGG")
#在螢幕上印出結果:abcGGG
zip
#可以將幾個可迭代物件(如串列)對應打包為一個新的元組
#如果參數串列的長度不相等,會以最少的數量為準做匹配,
-----------------------------
範例:
li=["a","b","c"]
li2 = ["AAA","BBB","CCC"]
zipdata = zip(li, li2)
for i,j in zipdata:
print(i,j)
#逐一輸出tuple的對應內容
print(zipdata)
#輸出tuple格式
print(list(zipdata))
#輸出串列格式
i,j = zip(*zip)
#將zip拆解開來,指定給i跟j兩條序列
```
---
## 自訂函式 function
``` python
def 名稱(參數1, 參數2 [,.....]):
程式內容
z = x + y
return z
#呼叫方式
def 名稱(參數1,參數2="sa"):
#將參數設預設值,有預設值的參數2在呼叫時不一定要寫,另外呼叫時也可以指定新的值給參數2
#參數也可以放串列,函式內也可以修訂串列內容,修訂後原串列也會跟著改變
#若是使用關鍵字行參數,呼叫時格式為 參數名稱=值,如 名稱(參數1='A',參數2='B')
def multivar(*參數):
#可以任意輸入1到多個參數
#如果普通參數和任意數量參數並存,必須將任意參數放在()的最右邊
#呼叫方式
multivar('AAA')
multivar('aaa','bbb','ccc')
#傳進去的參數格式是tuple元組
def multivar(**參數):
#使用任意數量的關鍵自行參數,可以自行輸入關鍵字
#此時參數格式為dict字典
#呼叫
multivar(city='AAA',lang='EN',locat='AMR')
-----------------------------
範例:
def a(var):
for i in var:
print(i)
mb = ["a","b","c"]
a(mb)
def a(var,g):
if g == 1:
var.append("dfdf")
return var
mb = ["a","b","c"]
a(mb,1)
#函數修改串列後,原串列會跟著改變
#採用以下寫法,原串列不會被改變
a(mb[:],1)
------------------------------
def fname(1, 3)
def fname(參數2="a",參數1="b")
#此方式可以讓參數的位置亂跳,但參數名稱需配合def後面的參數名稱
#有預設值得參數放後面,這樣呼叫時比較不會有順位的錯誤
def fname(參數1,參數2):
return 參數1-參數2
#回傳參數設計,回傳參數可以不只一個,用,分開
#如果沒有設定回傳值(return),則參數會預設傳回None
#回傳值可以是數值、字串、字典等
-----------------------------
範例:
def fname(參數1,參數2):
return 參數1+參數2,參數1-參數2,參數1*參數2,參數1/參數2
#呼叫
add, sub, mul, div =fname(20,10)
------------------------------
遞迴式函數設計
#每次呼叫自己時,會讓使用範圍越來越小
#必須有一個終止條件
-----------------------------
範例:
def fact(n):
if n == 1:
return 1
else:
return (n*fact(n-1))
#產生階乘運算(例如fact(5) 回傳1*2*3*4*5的值)
------------------------------
lambda
#稱為匿名函數,不需要函數名稱的函數
-----------------------------
範例:
vsqu = lambda s:s.replace('g', '')
#範例是輸入s,輸出s.replace('g', '')
#呼叫
print(vsqu("abcdefgh"))
------------------------------
```
* 區域變數:只有在該函數內使用,跳出函數外不能使用(該函數記憶體空間在函數執行完成後就刪除了)
* 全域變數:一般在主程式就建立,函數內也可以引用
* 如果區域變數和全域變數名稱相同,在函數內會使用區域變數的的值,在函數外則使用全域變數的值
---
## 函式庫 Package
``` python
#import 函式庫名稱
import datetime
datetime.datetime.now()
import ipywidgets as widgets
#ipysidgets是Jupyter上開發的可互動的函式庫,可以有拉桿、按鈕、點選等多種互動功能
# https://ipywidgets.readthedocs.io/en/latest/
```
---
## 流程控制
``` python
if (條件) :
程式
elif (條件) :
程式
else:
程式
list = [1,2,3,4]
for i in list
#和下列方法相同
for i in [1,2,3,4]
print(i)
for i in range(0,1000)
print(i)
#印出0到999,從0開始到end-1,所以是999
for i in range(0,1000,2)
##印出0到999,從0開始到end-1,間隔是2
for i,j in zip([1,2,3], [4,5,6]):
print(i,j)
#zip 可以一次用兩條序列來跑for迴圈,也可以三條......
break
#強制跳出for迴圈
continue
#符合條件就不執行本次運算,繼續執行下一次
#for i in range(20):
# if i < 10:continue
#輸出的值是超過10的才會輸出
else
#一旦for的條件都不能滿足時,就執行else的部分
#if i in range(3):
# print(i)
#else:
# print("over")
---------------------------------------------
範例:
squares = []
nn = list(range(n+1))
for i in nn:
squares.append(i ** 2)
可以濃縮成
square = [num ** 2 for num in range(1,n+1)]
尋找質數的範例
n = int(input("輸入數字"))
if n == 2:
print("%d是質數" % n)
else:
for i in range(2,n):
if n % i == 0:
print("%d不是質數" % n)
break
else:
print("%d是質數" % n)
----------------------------------------------
i = 0
while i < 8:
print(i)
i = i + 1
#印出0到7,主要是重複執行,並判斷條件是否成立(True),成立就繼續,不成立(False)就跳出
#如果設計變成無限迴圈,按Ctrl+C可以中斷
break
#強制離開迴圈
continue
#符合條件就不執行本次運算,繼續執行下一次
範例
while True:
#這種寫法會一直不斷重複,可搭配break做跳出
li = ["a","b","c","d"]
while li: #重複迴圈,直到li變成空串列
li.pop() #移除最後一個元素
```
---
## 運算子
* 關係運算子
> >= < <= == !=
* 邏輯運算子
and or not
---
## 類別 (物件導向)
* 類別名稱第一個字母必須大寫
* 類別中包含屬性(attribute)和方法(method)
* 類別中的方式是時就是自訂函數,但只有屬於該類別的物件可以調用,其他地方不能用
*
``` python
--------------------------------------------------
範例:
#基礎類別宣告與調用
class cy():
#cy後面的()也可以省略
title='OO國小'
def sname(n):
return n
#調用
print(cy.title)
print(cy.sname("AAA"))
--------------------------------------------------
#初始化類別的method,指宣告這個類別物件時,將自動執行這個方法,又稱建構元constructor
__init__()
--------------------------------------------------
範例:
class cy():
def __init__(self,uname,money):
self.name = uname
self.balance = money
self.title="taipei Bank"
#調用
bcla = cy("白先生",100)
print(bcla.title)
#呼叫類別時,會自動執行init方法,參數「白先生」會傳給init的uname,100會傳給money
#init的self是必須的,也必須放在所有參數最前面,初始化類別時會自動傳入這個參數,代表的是類別本身的物件
#未來在類別內想要參照各屬性與函數執行運算皆使用self
--------------------------------------------------
```
* 屬性
* 類別內的屬性可以讓外部引用的稱為共有屬性,可以讓外部引用的方法稱為公有方法,公有屬性可以在類別外修改
* 私有:無法在類別外修改私有類別屬性,也無法在類別外呼叫的私有方法
```python=
--------------------------------------------------
範例:
class cy():
def __init__(self,uname,money):
self.__name = uname
self.__balance = money
self.__title="taipei Bank"
print(self.__title)
#私有屬性
def __rcate(self,ud):
print(ud)
#私有方法,僅可以在類別內部被呼叫
def tod(self,rd):
self.__rcate(rd) #呼叫私有方法__rcate,並傳入rd參數
#調用
bcla = cy("白先生",100)
bcla.tod(123)
#類別內的屬性宣告時加上__即可變成,外部就無法修改了
--------------------------------------------------
```
* 繼承
* 被繼承的類別稱為父類別(parent class)或基底類別(base class)
* 繼承的類別稱為子類別(child class)或衍生類別(derived class)
* 優點是許多父類別的公有屬性或方法,在子類別中可以直接引用,另外子類別也可以有自己的屬性與方法
* 基底類別必須在衍生類別前面
* 衍生類別要取得基底類別的私有屬性,只能在基底類別使用return的方式將私有屬性包在方法內被呼叫
* 衍生類別也可以有自己的__init__方法,如果衍生和基底類別的方法或屬性名稱重複,會先使用衍生類別的,不行時再使用基底類別的
```python=
--------------------------------------------------
範例:
class cy():
def __init__(self,uname,money):
self.__name = uname
self.__balance = money
self.__title="taipei Bank"
#私有屬性
class shi(cy):
#繼承cy類別的屬性及方法
pass
#調用
bcla = shi("白先生",100)
print(bcla.title)
--------------------------------------------------
```
* 衍生類別使用基底類別方法
* super()
```python=
--------------------------------------------------
範例:
class A():
def __init__(self, aname, aage):
self.name = aname.title()
self.age = aage
print(self.name, self.age)
class B(A): #繼承基底類別A
def __init__(self,bname,bage):
super().__init__(bname,bage)
#使用A列別的init方法,變數不用加self.
#直接將變數傳給A類別的init方法處理
#加上super()可以繼承A類別的所有屬性及方法
三層的使用:
class A():
def __init__(self):
self.Aname = "AAA"
def get_info1(self):
print('A class is', self.Aname)
class B(A): #繼承A類別
def __init__(self):
self.Bname = "BBB"
super().__init__() # 將A類別的init複製,B類別就有A類別的屬性
def get_info2(self):
print('B class is', self.Bname)
class C(B): #繼承B類別
def __init__(self):
self.Cname = "CCC"
super().__init__() # 將B類別的init複製,C類別就有A跟B類別的屬性,若是方法method就不需要用這個,直接繼承
def get_info3(self):
print('C class is', self.Cname)
tt = C()
tt.get_info1()
旁枝的使用
class A():
def __init__(self):
self.Aname = "AAA"
class BA(A): #繼承A類別
def __init__(self):
self.Bname = "BBB"
super().__init__() # 將A類別的init複製
class CA(A): #繼承A類別
def __init__(self):
self.Cname = "CCC"
super().__init__() # 將A類別的init複製
def get_info(self):
print("A name is",self.Aname,
"\n B name is",BA().Bname, #取得旁枝BA類別的屬性,記得加上()
"\n C name is",self.Cname)
tt = CA()
tt.get_info()
多重繼承
class A():
def __init__(self):
self.name = "FA"
def info1(self):
self.Aname = "Aname"
print("A")
class BA(A): #繼承A類別
def info2(self):
self.BAname = "BAname"
print("BA")
class CA(A): #繼承A類別
def __init__(self):
super().__init__() # 將A類別的init複製
def info3(self):
self.CAname = "CAname"
print("CA")
class DBC(BA,CA): #同時繼承BA跟CA類別
def __init__(self):
super().__init__() # 將CA類別的init複製,同時可擁有A類別的init屬性
self.DBCname = "DBCname"
def info4(self):
print("DBC")
t = DBC()
print(t.DBCname)
t.info1()
print(t.name)
--------------------------------------------------
isinstance(物件, 類別)
#查詢物件是否屬於該類別,是的話返回True
#有繼承時,子類別的物件屬於父類別時(True),但父類別的物件並不一定屬於子類別
--------------------------------------------------
依上面範例:
isinstance(t,DBC) #返回True
isinstance(t,A) #返回True,有繼承關係
Y = CA()
isinstance(Y,DBC) #返回False,繼承關係是從上到下,下屬于上,上不屬於下
--------------------------------------------------
```
---
## 特殊方法
``` python
__doc__
#列出文檔內的 ''' ''' 標示的註解
__name__
#判斷程式是自己執行或是被import當成模組使用
#自己執行時,__name__ = __main__
#當成模組使用時,輸出模組名稱
__str__()
#可以協助返回較容易讀取的字串
--------------------------------------------------
範例:
class name:
def __init__(self,bn):
self.name = bn
def __str__(self): #定義返回容易閱讀的字串
return self.name
t = name("Hang")
print(t)
#有__str__返回 Hang
#沒有__str__返回 <__main__.name object at 0x10e5340d0>
--------------------------------------------------
__repr__()
#和__str__方法相同,因為單純在python Shell,系統會呼叫shell做回應
#可以在class內寫上 __repr__ = __str__
__iter__()
#將類別設計成迭代物件(類似list),提供for使用,會搭配next()及raise Stoplteration
--------------------------------------------------
範例:
class Fib():
def __init__(self,max):
self.max = max
def __iter__(self):
self.a = 0
self.b = 1
return self
def __next__(self):
fib = self.a
if fib > self.max:
raise StopIteration
self.a, self.b = self.b, self.a + self.b
return fib
for i in Fib(100):
print(i)
--------------------------------------------------
```
---
## 模組
* 模組安裝:在python shell內輸入 pip install 模組名稱
* 模組更新:pip install -U 模組名稱
* mac安裝:sudo pip3 install 模組名稱
* 將類別或函數寫好後,另存成 模組名稱.py 的檔案即可
* 呼叫時使用:
import 模組名稱
使用時要用 模組名稱.函數名稱 或是 模組名稱.類別名稱
* 也可以僅呼叫模組內的個別函數或個別類:
from 模組名稱 import 函數名稱
from 模組名稱 import 類別名稱
(未來程式內引用時可以不寫模組名稱)
* 導入多個函數或類別:
from 模組名稱 import 函數名稱1,函數名稱2,函數名稱3......
from 模組名稱 import 類別名稱1,類別名稱2,類別名稱3......
* 導入模組內所有函數或類別
from 模組名稱 import *
此方法和import 模組名稱 大略相同,不同的是未來程式內引用時可以不寫模組名稱
* 替代名稱 as
import 模組名稱 as 替代名稱
from 模組名稱 import 函數名稱 as 替代名稱
* 如果匯入的模組超過1個,而且這些模組之間有繼承的關係,那都要import才行
---
## 檔案處理
* 使用os或os.path模組
```python
os.getcwd()
#取得現在的所在目錄
os.path.abspath(檔名)
#取的檔案的絕對路徑
--------------------------------------------------
範例:
print(os.path.abspath('.'))
#目前所在資料夾的絕對路徑
print(os.path.abspath('..'))
#目前所在位置的上一層資料夾絕對路徑
print(os.path.abspath('Untitled1.ipynb'))
#該檔案的絕對路徑
--------------------------------------------------
os.path.relpath(path, start)
#傳回從start(檔案或位置)到path的相對路徑清單
#若start省略,則傳會工作目錄到path間的相對路徑清單
#anaconda並不會正確顯示
os.path.basename(path)
#去除目錄的路徑,回傳檔案名稱(包含附檔名)
os.path.exists(path)
#path的檔案或資料夾如果存在傳回True,否則傳回Fase
os.path.isabs(path)
#path的檔案或資料夾是絕對路徑傳回True,否則傳回Fase(mac根目錄前要加上/,例如/Users/ycp/Desktop/質因數.ipynb)
os.path.isdir(path)
#path是資料夾傳回True,否則傳回Fase,(path要用絕對路徑)
os.path.isfile(path)
#path是檔案傳回True,否則傳回Fase
os.mkdir(path)
#建立path的目錄,建議搭配os.path.exists檢查目錄是否已存在
os.rmdir(path)
#刪除path目錄,限制只能是空的目錄
os.remove(path)
#刪除path檔案
os.chdir(path)
#切換目前工作資料夾到path
os.path.join(參數1, 參數2, 參數3,......)
#將參數內的字串結合成一個檔案路徑
os.path.getsize(檔名)
#取得檔案的大小,單位是位元組
os.listdir()
#以串列方式列出該目錄的內容
os.walk(path)
#列出該path之下所有的檔案和資料夾(目錄數)
#返回迭代物件,每一個包含3個值:工作目錄名稱(字串),該工作目錄下所有的子目錄(串列),,該工作目錄下所有的檔案(串列)
--------------------------------------------------
範例:
import os
for dirname, subd, fname in os.walk('finlab_course/'):
#for 後面的順序不可以亂,但名稱可以自取
print("工作目錄名稱:",dirname)
print("子目錄名稱串列",subd)
print("檔案串列",fname)
--------------------------------------------------
```
* 關於檔案的常用函數(不用引入os)
```python
open(path, mode="r")
open(path, "w")
open(path, "w", encoding="utf-8")
#開啟一個檔案,mode有不同開啟選項,不寫就是r
#如果檔案不存在,又是w模式,則open會建立該檔案,若檔案存在,則會清空該檔案
#r讀取,w覆蓋式寫入,a附加式寫入,x開啟一個新的檔案提供寫入(如果檔案已經存在會產生錯誤)
#b開啟按進為檔案模式,t開啟文字檔案模式,+開啟檔案供更新用
#微軟系統的ANSI編碼為cp950(encoding="950")
#encoding = "utf-8-sig" 採用LE的BOM編碼系統
# http://mt116.blogspot.com/2017/08/coding-system-unicode.html
read()
#讀取檔案內容
close()
#關閉檔案
with open(path) as 檔案物件 :
#此方法也可檔案物件,但是可以不必關閉檔案,系統會在不需要此檔案時自動將檔案關閉
readlines()
#逐行讀取檔案內容,以串列方式儲存,每行的換行字元皆會儲存在串列內
find(字串)
#搜尋字串是否有在目標字串內,回傳找到的索引位置(從0開始)
write(輸出的資料)
#輸出資料寫入到檔案內,無法寫入數值資料,要寫入資料請將數值轉字串
#輸出多行資料,請逐行寫write,如果要斷行請在每行最後加上\n
-----------------------------
範例:
file_obj = open('test.html')
data = file_obj.read()
file_obj.close()
print(data)
#可以改寫如下
with open('test.html') as file_obj:
data = file_obj.read()
print(data)
#逐行讀取檔案內容
with open('test.html') as file_obj:
for i in file_obj:
print(i)
#另一種寫法
objlist = file_obj.readlines()
#readlines之前不可以有read,不然讀不出來
print(objlist)
#搜尋數據
a = "abcd"
b = "c"
if b in a:
print("ok")
#或是使用
index = a.find(b)
if index >= 0:
print("ok")
#數值寫入檔案的方法
with open('test.html') as file_obj:
file_obj.write(str(100)+'\n')
file_obj.write("ABC")
-----------------------------
```
* 使用glob模組
```python
import glob
glob.glob
#獲得特定資料夾的的內容,返回串列
#可以使用萬用字元*
--------------------------------------------------
範例:
glob.glob('/Users/ycp/Desktop/*')
glob.glob('*.txt')
glob.glob('Untitled*.ipynb')
--------------------------------------------------
```
* 使用shutil模組
* 檔案或目錄的複製、刪除、更動位置、更改名稱
```python
import shutil
shutil.copy(source, destination)
#檔案複製,複製時source檔一定要存在
shutil.copytree(source, destination)
#目錄複製,複製時source目錄一定要存在,複製時連同裡面的資料也會複製
shutil.move(source, destination)
#檔案移動,移動時source檔一定要存在,移動後,source檔案不再存在,source跟destination的名稱不一定要相同
#也可以用來改檔名或目錄名
#也可以移動目錄,移動時連同該目錄下的子目錄也會一並移動
#移動目錄時也可以同時改名
shutil.rmtree(目錄名稱)
#刪除底下有資料的目錄,刪除就是刪除,不會在垃圾桶
--------------------------------------------------
範例:
import shutil
shutil.move("t2.txt", "./gg")
#移動t2.txt到同位置的gg子目錄內,寫成.//gg亦可
shutil.move("t2.txt", "t3.txt")
#更改檔案名稱
--------------------------------------------------
```
* 使用send2trash模組
```python
import send2trash
send2trash.send2trash(目錄名稱)
#刪除底下有資料的目錄,刪除後會在垃圾桶
```
* 使用zipFile模組
* 檔案或目錄壓縮或解壓縮
```python
import zipfile
fz = zipfile.ZipFile("dn.zip", "w")
#先建立物件,fz是物件名稱,dn.zip是未來輸出的zip檔
# w 代表未來是供write方法寫入
# zipfile()無法執行整個目錄直接壓縮,因此採用迴圈方式逐一寫入zip檔
namelist()
#傳回zip檔案內所有被壓縮的檔案或目錄名稱,以串列方式傳回此物件
infolist()
#搭配namelist(),傳回個元素的屬性,檔案名稱filename,檔案大小file_size,壓縮結果大小compress_size,檔案時間date_time
extractall()
#解壓縮zip檔
--------------------------------------------------
範例:
import zipfile,glob,os
with zipfile.ZipFile('archive.zip', 'w') as zf:
for i in glob.glob("/Users/ycp/Desktop/t*"):#逐一處理gg資料夾的所有檔案
zf.write(i, os.path.basename(i), zipfile.ZIP_DEFLATED)
# zipfile.ZIP_DEFLATED 是壓縮方式
zf.close #關閉物件
#讀取壓縮檔案內檔案的各項屬性
import zipfile
listfile = zipfile.ZipFile("archive.zip", "r")
print(listfile.namelist()) #以串列方式列出檔案名稱
for i in listfile.infolist():
print(i.filename, i.file_size, i.compress_size, i.date_time)
#逐一列出各項屬性
#解壓縮zip檔案
listfile = zipfile.ZipFile("archive.zip")
listfile.extractall('out') #解壓縮後的資料夾名稱
listfile.close
--------------------------------------------------
```
* 使用pyperclip剪貼簿模組
```python
pip install pyperclip
#安裝模組
--------------------------------------------------
範例:
import pyperclip
pyperclip.copy("AAA") #將字串拷貝到剪貼簿
string = pyperclip.paste() #將剪貼簿拷貝回string
print(string)
--------------------------------------------------
```
---
## 程式錯誤(異常)處理與LOG紀錄
* 一般城市有錯誤或異常時,或印出錯誤訊息,並停止程式繼續執行,使用異常處理時,有捕捉到異常資訊時,會執行異常處理部分的指令,和後跳過異常的那一行繼續執行下一行
* 錯誤說明:
* AttributeError 通常指物件沒有這個屬性
* Exception 一般錯誤皆可使用,可以提供捕捉各種基礎異常用
* FileNotFoundError 找不到檔案
* IOError 在輸入或輸出時發生錯誤
* IndexError 索引超出範圍區間
* KeyError 在映射中沒有這個鍵
* MemoryError 需求記憶體空間超出範圍
* NameError 物件名稱未宣告
* SyntaxError 語法錯誤
* SystemError 直譯器的系統錯誤
* TypeError 資料型別錯誤
* ValueError 傳入無效參數
* ZeroDivisionError 除數不可以為0
```python
def division(x, y):
try:
return x/y #指令或處理程序
except ZeroDivisionError: # 捕捉到異常
print("除數不可以為0") # 異常時執行此列
#回傳一個None
finally:
print("階段任務完成")
#finally不一定要寫
#有寫時,這個try之下一定會執行finally
#在def之下,如果無誤會先回傳finally內容,再傳回try,如果有異常,先執行except,再執行finally,最後返回主程式輸出None
print(division(10,2)) # 參數無誤,執行return x/y
print(division(5,0)) # 除數為0,執行異常處理程序
print(division(6,2)) #上一行錯誤跳過後繼續處理這一行
#將上面的改寫成:
#增加程式的可讀性
def division(x, y):
try:
ans = x/y #先處理此程序
except ZeroDivisionError: # 捕捉到異常
print("除數不可以為0") # 異常時執行此列
else:
return ans #如果無誤執行此程序
#分析檔案開啟錯誤
fn="test.txt"
try:
with open(fn) as file_obj:
data = file_obj.read()
except FileNotFoundError:
print("找不到%s檔案"%fn)
except TypeError: #可以設定不只一個錯誤捕捉
print("資料型別錯誤")
except (FileNotFoundError, TypeError):
#一個except同時捕捉多的錯誤
print("有錯誤")
else:
wordnum = data.spilt()
print("字數:", len(wordnum))
#使用內建的錯誤訊息
def division(x, y):
try:
return x/y
except ZeroDivisionError as e:
# 使用python內建異常或錯誤訊息
print(e)
#捕捉所有異常
def division(x, y):
try:
return x/y
except:
print("有異常")
#會回傳一個None
```
* 自行定義抹些狀況為異常,丟出異常訊息,程式停止往下執行,同時讓程式跳到自行設計的except去執行
```python
raise exception("自訂的錯誤訊息")
......
try:
指令
except Exception as err:
#err是任意取名的變數,內容就是raise exception後面的訊息
指令
#範例,搭配traceback模組將錯誤資訊記錄在檔案中
import traceback
def passwd(pwd):
pwdlen = len(pwd)
if pwdlen < 5:
raise Exception("密碼長度不足")
if pwdlen > 8:
raise Exception("密碼長度太長")
print("密碼長度正確")
try:
passwd("aabbccdd")
except Exception as err:
errlog = open("errlog.txt","a")
errlog.write(traceback.format_exc()) #寫入錯誤資訊內容
errlog.close()
print(err)
assert 條件, '字串'
#程式檢查點
#程式執行至此,需滿足條件(True),才可以繼續執行
#如果執行無法滿足條件(False),程式會泡出異常,並印出後面的字串
for i in range(100):
assert i<=20 ,'i大於20'
print(i)
#讓系統停止assert運作
#找到phthon.exe(windows下)存放的資料夾,在cmd模式下,切換到該資料夾,並輸入
# python.xe -O D:\pdata\ch12.py
# -O 後面是指要執行中斷assert的程式路徑
```
* 程式LOG
* logging模組5個等級(上到下。由小到大)
* DEBUG:顯示最低層級的內容
* INFO:紀錄一般發生的事件
* WARNING:顯示的內容不會影響程式執行,但未來可能導致問題發生
* ERROR:程式在某些狀態引發錯誤的原因
* CRITIAL:通常顯示將會讓整個系統當掉或中斷的錯誤
```python
import logging
#使用下列函數設定顯示資訊的等級,為來只有此等級或更高等級的LOG會被顯示
lgooing.basicConfig(level=logging.DEBUG) #DEBUG等級
#指令
logging.debug('字串')
logging.info('字串')
logging.warning('字串')
logging.error('字串')
logging.critical('字串')
#印出的結果會有前導訊息,如 DEFUB:root:
lgooing.basicConfig(level=logging.DEBUG, format=' ')
#加上 format=' ' 可以取消前導訊息
lgooing.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s : %(message)s')
#訊息前面加上紀錄時間及顯示層級
#anaconda中,若level有修改,要restart kernel才會正確顯示
logging.basicConfig(filename='logout.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s : %(message)s')
#filename可以將log存在檔案內,但此時螢幕就不會出現log訊息
#重複執行時,後面的log會在檔案接下去寫入
#須參考層級,如果低於設定的level,也不會存入檔案內
範例:
import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s : %(message)s')
logging.debug('程式開始')
for i in range(5):
logging.debug('目前索引 %s' %i)
logging.debug('程式結束')
logging.disable(level)
#停用log,level是指層級
logging.disable(logging.CRITIAL)
```
## 正規表達式 Regular Expression
* 使用 re 模組
* https://docs.python.org/2/library/re.html
* 規則說明:
* \d 表示0-9數字字元
* \d+ 表示不限長度的數字(使用+,其他規則類推)
* \D 除了0-9之間的整數字元以外的其他字元
* \s 空白、定位、Tab鍵、換行、換頁字元
* \S 除了空白、定位、Tab鍵、換行、換頁字元之外的其他字元
* \w 數字、字母和底線_字元[A-Za-z0-9_]
* \W 除了數字、字母和底線_字元[A-Za-z0-9_]之外的其他字元
* | 或者 'mary|john' 表示mary或john皆符合,字串周邊不可以有空格
* (字串?) ()內的可有可無,皆算符合 (\d?)
* (字串*) ()內的字串出現0到多次皆符合 (\w*)
* (字串+) ()內的字串出現1到多次皆符合,和*不同的是至少要有1次,否則回傳None (\s+)
* \d{4} 4個數字,{}內是重複次數
* 字元分類形式,[ ]內不需使用\
* [a-z] 搜尋a-z的小寫字元
* [A-Z] 搜尋A-Z的大寫字元
* [aeiouAEIOU] 搜尋aeiouAEIOU這10個字元
* [2-5.] 搜尋2-5的數字和 . (在[]內不用寫成\.)
* [^ ] []加上^,搜尋不在[]內規則的所有字元
* '^字串' ''前面加上^,表示搜尋的字串必須出現在被搜尋字串的起始位置才算成功
* '字串$' ''後面加上$,表示搜尋的字串必須出現在被搜尋字串的最後位置才算成功
* '^字串$' 前後都加,被搜尋的句子一定只有一個字串
* '.字串' .是萬用字元,代表除了換行字元之外的所有字元,但是只有一個字元(搜尋符號.要使用\.)
* '.' 搜尋所有字元,換行字元除外
* re.DOTALL 可以搜尋包括換行字元,放在search(),findall(),compiler()的Flags位置
* re.VERBOSE 可以在pattern規則內分行時加上註解
* re.I 或是 re.IGNORECASE 忽略字母大小寫
```python=
import re
word = r'\d\d\d\d-\d\d\d-\d\d\d' #定義規則
ckrule = re.compile(word) #建立規則物件
# ckrule = re.compile(r'\d\d\d\d-\d\d\d-\d\d\d')
msg1 = "我的電話是0932-321-123"
msg2 = "我有兩隻電話:0955-234-543,0977-778-543,你保留一下"
for i in range(1,3):
pnum = ckrule.search(locals()['msg%s'%i])
#使用search搜尋字串中符合的規則的
# locals()['msg%s'%i]是動態設定變數名稱msg1,msg2
#search只會找到第一組相符的,第二組以後的不會找
#回傳格式 <re.Match object; span=(5, 17), match='0932-321-123'>
#沒有相符的傳回None
print(pnum)
pnum = ckrule.findall(locals()['msg%s'%i])
#search也可以改用findall,會找全部相符的
#回傳格式串列 ['0955-234-543', '0977-778-543'],沒有相符的傳回None
#上面範例也可以改寫如下
import re
word = r'\d{4}-\d{3}-\d{3}'
#規則可以改寫成這樣的,相同的用{}填入數字
msg1 = "我的電話是0932-321-123"
msg2 = "我有兩隻電話:0955-234-543,0977-778-543,你保留一下"
for i in range(1,4):
pnum = re.findall(word, locals()['msg%s'%i])
#減少compile,直接使用re
#格式是re.findall(規則, 字串, Flags),Flags可以省略
#格式是re.search(規則, 字串, Flags),Flags可以省略
print(pnum)
#搜尋結果轉成tuple
import re
word = r'(\(\d{2}\))(\d{8})'
msg1 = "我的電話是(02)12345678"
msg2 = "我有兩隻電話:(03)12345678,(03)87654321,你保留一下"
for i in range(1,3):
pnum = re.search(word, locals()['msg%s'%i])
pnumf, pnumb = pnum.groups()
#pnum.groups()的格式是tuple
#可以多項指定,也可以使用pnum.groups(0) 類推
print(pnumf,pnumb)
#search可以搭配group()或group(n)取出相符的子字串,例如規則是'John(son|pon|agr)'
word='john(son|per|iqe)(aa|bb)'
msg = "I see johnsonaa ,johnperbb and johnppdcc go to out room"
mtw = re.search(word, msg)
print(mtw)
print(mtw.group())
print(mtw.group(1)) #son
print(mtw.group(2)) #aa
#使用?查詢,範例import re
word = r'(\(\d{2}\))?(\d{8})'
msg1 = "我的電話是(02)12345678"
msg2 = "我有兩隻電話:12345678,(03)87654321,你保留一下"
for i in range(1,3):
pnum = re.findall(word, locals()['msg%s'%i])
print(pnum)
#使用?查詢
word = 'john((gg)*son)'
msg = "I call johnggggggson"
pnum = re.search(word, msg)
print(pnum.group())
#搜尋忽略字母大小寫
word = 'john|TOM'
msg = "John, tom and Mary"
pnum = re.findall(word, msg, re.I)
#Flag位置寫re.I 或是 re.IGNORECASE 皆可
print(pnum)
#重複次數範例
(son){3} #搜尋'sonsonson',所以'sonsons'不符合
(son){2,4} #搜尋'sonson','sonsonson','sonsonsonson'皆符合
(son){2,} #son重複2次以上皆符合(含2次)
(son){,10} #son重複10次以下皆符合(含10次)
範例
pattern = '(son){3,5}'
#貪婪模式:python預設模式,以下範例執行會找出'sonsonsonsonson'(最多符合的)
pattern = '(son){3,5}?'
#非貪婪模式:以下範例執行會找出'sonsonson'(最少符合的)
msg = 'sonsonsonsonson'
txt = re.search(pattern, msg)
print(txt.group())
MatchObject物件
re.match
#和re.search功能相同,不同的是re.match搜尋字串最前面,找不到就回傳None
#使用match和search搜尋成功時可用
txt = re.match(pattern, msg)
txt.group() #傳回搜尋到字串
txt.end() #傳回搜尋到字串的結束位置
txt.start() #傳回搜尋到字串的起始位置
txt.span() #傳回搜尋到字串的(起始,結束)位置
result = re.sub(pattern, newstr, msg)
#pattern取代規則
#newstr要更換的新內容
#msg搜尋的字串
#搜尋成功時,將結果字串傳給result,原msg不受影響
#搜尋到多筆相同字串時,這些字串全部被取代
#搜尋失敗,將msg內容傳給result
範例
import re
pattern = r'CIA (\w)\w*'
newstr = r'\1***' #\1表示第一組對映(\w)使用原字,剩下的\w*全用***
msg = 'CIA Mark , CIA Mary, CIA John'
txt = re.sub(pattern, newstr, msg)
print(txt)
#印出 M*** , M***, J***
#Flag同時放許多參數
dstr = re.search(pattern, msg, re.VERBOSE|re.IGNORECASE|re.DOTALL)
比較複雜的正規是表達範例
#電話號碼處理
pattern = r'''(
(\d{2}|\(\d{2}\))? #區域號碼,可省略
(\s|-)? #分隔符號(-或是空格),可省略
\d{8} #電話號碼
(\s*(ext|ext.)\s*\d{2,4})? #分機號碼2-4位數號碼
)'''
#電子郵件搜尋
pattern = r'''(
[a-zA-Z0-9_.]+ #帳號
@ # @ 符號
[a-zA-Z0-9_.]+ #domain
\. # . 符號
[a-zA-Z]{2,4} #機構分類com edu等
([\.])? # . 符號,可省略
([a-zA-Z]{2,4})? #國碼,美國是省略的
)'''
```
###### tags: `PYTHON`