本節大綱
- 迭代器&生成器
- 裝飾器
- 基本裝飾器
- 多參數裝飾器
- 遞歸
- 算法基礎:二分查找、二維數組轉換
- 正則表達式
- 常用模塊學習
- 作業:計算器開發
- 實現加減乘除及拓號優先級解析
- 用戶輸入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等類似公式后,必須自己解析里面的(),+,-,*,/符號和公式,運算后得出結果,結果必須與真實的計算器所得出的結果一致
迭代器&生成器
迭代器
迭代器是訪問集合元素的一種方式。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會后退,不過這也沒什么,因為人們很少在迭代途中往后退。另外,迭代器的一大優點是不要求事先准備好整個迭代過程中所有的元素。迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之后,元素可以不存在或者被銷毀。這個特點使得它特別適合用於遍歷一些巨大的或是無限的集合,比如幾個G的文件
特點:
- 訪問者不需要關心迭代器內部的結構,僅需通過next()方法不斷去取下一個內容
- 不能隨機訪問集合中的某個值 ,只能從頭到尾依次訪問
- 訪問到一半時不能往回退
- 便於循環比較大的數據集合,節省內存
生成一個迭代器:
>>> a = iter([1,2,3,4,5]) >>> a <list_iterator object at 0x101402630> >>> a.__next__() 1 >>> a.__next__() 2 >>> a.__next__() 3 >>> a.__next__() 4 >>> a.__next__() 5 >>> a.__next__() Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
Repeated calls to the iterator’s __next__()
method (or passing it to the built-in function next()
) return successive items in the stream. When no more data are available a StopIteration
exception is raised instead. At this point, the iterator object is exhausted and any further calls to its __next__()
method just raise StopIteration
again.
生成器generator
定義:一個函數調用時返回一個迭代器,那這個函數就叫做生成器(generator),如果函數中包含yield語法,那這個函數就會變成生成器
代碼:
def cash_out(amount): while amount >0: amount -= 1 yield 1
print("擦,又來取錢了。。。敗家子!") ATM = cash_out(5) print("取到錢 %s 萬" % ATM.__next__()) print("花掉花掉!") print("取到錢 %s 萬" % ATM.__next__()) print("取到錢 %s 萬" % ATM.__next__()) print("花掉花掉!") print("取到錢 %s 萬" % ATM.__next__()) print("取到錢 %s 萬" % ATM.__next__()) print("取到錢 %s 萬" % ATM.__next__()) #到這時錢就取沒了,再取就報錯了 print("取到錢 %s 萬" % ATM.__next__())
作用:
這個yield的主要效果呢,就是可以使函數中斷,並保存中斷狀態,中斷后,代碼可以繼續往下執行,過一段時間還可以再重新調用這個函數,從上次yield的下一句開始執行。
另外,還可通過yield實現在單線程的情況下實現並發運算的效果
import time def consumer(name): print("%s 准備吃包子啦!" %name) while True: baozi = yield print("包子[%s]來了,被[%s]吃了!" %(baozi,name)) def producer(name): c = consumer('A') c2 = consumer('B') c.__next__() c2.__next__() print("老子開始准備做包子啦!") for i in range(10): time.sleep(1) print("做了2個包子!") c.send(i) c2.send(i) producer("alex")
裝飾器
直接 看銀角大王寫的文檔 http://www.cnblogs.com/wupeiqi/articles/4980620.html
遞歸
特點
要求
def binary_search(data_list,find_num): mid_pos = int(len(data_list) /2 ) #find the middle position of the list mid_val = data_list[mid_pos] # get the value by it's position print(data_list) if len(data_list) >1: if mid_val > find_num: # means the find_num is in left hand of mid_val print("[%s] should be in left of [%s]" %(find_num,mid_val)) binary_search(data_list[:mid_pos],find_num) elif mid_val < find_num: # means the find_num is in the right hand of mid_val print("[%s] should be in right of [%s]" %(find_num,mid_val)) binary_search(data_list[mid_pos:],find_num) else: # means the mid_val == find_num print("Find ", find_num) else: print("cannot find [%s] in data_list" %find_num) if __name__ == '__main__': primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] binary_search(primes,67)
在后面的故事我就編不下去啦,哈哈!but anyway,以上就是典型的遞歸用法,在程序里自己調用自己。
算法基礎
#!_*_coding:utf-8_*_ array=[[col for col in range(5)] for row in range(5)] #初始化一個4*4數組 #array=[[col for col in 'abcde'] for row in range(5)] for row in array: #旋轉前先看看數組長啥樣 print(row) print('-------------') for i,row in enumerate(array): for index in range(i,len(row)): tmp = array[index][i] #get each rows' data by column's index array[index][i] = array[i][index] # print tmp,array[i][index] #= tmp array[i][index] = tmp for r in array:print r print('--one big loop --')
冒泡排序
將一個不規則的數組按從小到大的順序進行排序
data = [10,4,33,21,54,3,8,11,5,22,2,1,17,13,6] print("before sort:",data) previous = data[0] for j in range(len(data)): tmp = 0 for i in range(len(data)-1): if data[i] > data[i+1]: tmp=data[i] data[i] = data[i+1] data[i+1] = tmp print(data) print("after sort:",data)
(1)時間頻度 一個算法執行所耗費的時間,從理論上是不能算出來的,必須上機運行測試才能知道。但我們不可能也沒有必要對每個算法都上機測試,只需知道哪個算法花費的時間多,哪個算法花費的時間少就可以了。並且一個算法花費的時間與算法中語句的執行次數成正比例,哪個算法中語句執行次數多,它花費時間就多。一個算法中的語句執行次數稱為語句頻度或時間頻度。記為T(n)。
for (i=1; i<=n; i++) x++; for (i=1; i<=n; i++) for (j=1; j<=n; j++) x++;
第一個for循環的時間復雜度為Ο(n),第二個for循環的時間復雜度為Ο(n2),則整個算法的時間復雜度為Ο(n+n2)=Ο(n2)。
常數時間
若對於一個算法,的上界與輸入大小無關,則稱其具有常數時間,記作
時間。一個例子是訪問數組中的單個元素,因為訪問它只需要一條指令。但是,找到無序數組中的最小元素則不是,因為這需要遍歷所有元素來找出最小值。這是一項線性時間的操作,或稱
時間。但如果預先知道元素的數量並假設數量保持不變,則該操作也可被稱為具有常數時間。
對數時間
若算法的T(n) = O(log n),則稱其具有對數時間
對數時間的算法是非常有效的,因為每增加一個輸入,其所需要的額外計算時間會變小。
遞歸地將字符串砍半並且輸出是這個類別函數的一個簡單例子。它需要O(log n)的時間因為每次輸出之前我們都將字符串砍半。 這意味着,如果我們想增加輸出的次數,我們需要將字符串長度加倍。
線性時間
如果一個算法的時間復雜度為O(n),則稱這個算法具有線性時間,或O(n)時間。非正式地說,這意味着對於足夠大的輸入,運行時間增加的大小與輸入成線性關系。例如,一個計算列表所有元素的和的程序,需要的時間與列表的長度成正比。
正則表達式
import re #導入模塊名 p = re.compile("^[0-9]") #生成要匹配的正則對象 , ^代表從開頭匹配,[0-9]代表匹配0至9的任意一個數字, 所以這里的意思是對傳進來的字符串進行匹配,如果這個字符串的開頭第一個字符是數字,就代表匹配上了 m = p.match('14534Abc') #按上面生成的正則對象 去匹配 字符串, 如果能匹配成功,這個m就會有值, 否則m為None
if m: #不為空代表匹配上了 print(m.group()) #m.group()返回匹配上的結果,此處為1,因為匹配上的是1這個字符
else:
print("doesn't match.")
上面的第2 和第3行也可以合並成一行來寫:
m = p.match("^[0-9]",'14534Abc')
效果是一樣的,區別在於,第一種方式是提前對要匹配的格式進行了編譯(對匹配公式進行解析),這樣再去匹配的時候就不用在編譯匹配的格式,第2種簡寫是每次匹配的時候 都 要進行一次匹配公式的編譯,所以,如果你需要從一個5w行的文件中匹配出所有以數字開頭的行,建議先把正則公式進行編譯再匹配,這樣速度會快點。
匹配格式
模式 | 描述 |
---|---|
^ | 匹配字符串的開頭 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了換行符,當re.DOTALL標記被指定時,則可以匹配包括換行符的任意字符。 |
[...] | 用來表示一組字符,單獨列出:[amk] 匹配 'a','m'或'k' |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
re* | 匹配0個或多個的表達式。 |
re+ | 匹配1個或多個的表達式。 |
re? | 匹配0個或1個由前面的正則表達式定義的片段,非貪婪方式 |
re{ n} | |
re{ n,} | 精確匹配n個前面表達式。 |
re{ n, m} | 匹配 n 到 m 次由前面的正則表達式定義的片段,貪婪方式 |
a| b | 匹配a或b |
(re) | G匹配括號內的表達式,也表示一個組 |
(?imx) | 正則表達式包含三種可選標志:i, m, 或 x 。只影響括號中的區域。 |
(?-imx) | 正則表達式關閉 i, m, 或 x 可選標志。只影響括號中的區域。 |
(?: re) | 類似 (...), 但是不表示一個組 |
(?imx: re) | 在括號中使用i, m, 或 x 可選標志 |
(?-imx: re) | 在括號中不使用i, m, 或 x 可選標志 |
(?#...) | 注釋. |
(?= re) | 前向肯定界定符。如果所含正則表達式,以 ... 表示,在當前位置成功匹配時成功,否則失敗。但一旦所含表達式已經嘗試,匹配引擎根本沒有提高;模式的剩余部分還要嘗試界定符的右邊。 |
(?! re) | 前向否定界定符。與肯定界定符相反;當所含表達式不能在字符串當前位置匹配時成功 |
(?> re) | 匹配的獨立模式,省去回溯。 |
\w | 匹配字母數字 |
\W | 匹配非字母數字 |
\s | 匹配任意空白字符,等價於 [\t\n\r\f]. |
\S | 匹配任意非空字符 |
\d | 匹配任意數字,等價於 [0-9]. |
\D | 匹配任意非數字 |
\A | 匹配字符串開始 |
\Z | 匹配字符串結束,如果是存在換行,只匹配到換行前的結束字符串。c |
\z | 匹配字符串結束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\n, \t, 等. | 匹配一個換行符。匹配一個制表符。等 |
\1...\9 | 匹配第n個分組的子表達式。 |
\10 | 匹配第n個分組的子表達式,如果它經匹配。否則指的是八進制字符碼的表達式。 |
正則表達式常用5種操作
re.match(pattern, string) # 從頭匹配
re.search(pattern, string) # 匹配整個字符串,直到找到一個匹配
re.split() # 將匹配到的格式當做分割點對字符串分割成列表
>>>m = re.split("[0-9]", "alex1rain2jack3helen rachel8") >>>print(m)
輸出: ['alex', 'rain', 'jack', 'helen rachel', '']
re.findall() # 找到所有要匹配的字符並返回列表格式
>>>m = re.findall("[0-9]", "alex1rain2jack3helen rachel8") >>>print(m)
輸出:['1', '2', '3', '8']
re.sub(pattern, repl, string, count,flag) # 替換匹配到的字符
m=re.sub("[0-9]","|", "alex1rain2jack3helen rachel8",count=2 ) print(m)
輸出:alex|rain|jack3helen rachel8
正則表達式實例
字符匹配
實例 | 描述 |
---|---|
python | 匹配 "python". |
字符類
實例 | 描述 |
---|---|
[Pp]ython | 匹配 "Python" 或 "python" |
rub[ye] | 匹配 "ruby" 或 "rube" |
[aeiou] | 匹配中括號內的任意一個字母 |
[0-9] | 匹配任何數字。類似於 [0123456789] |
[a-z] | 匹配任何小寫字母 |
[A-Z] | 匹配任何大寫字母 |
[a-zA-Z0-9] | 匹配任何字母及數字 |
[^aeiou] | 除了aeiou字母以外的所有字符 |
[^0-9] | 匹配除了數字外的字符 |
特殊字符類
實例 | 描述 |
---|---|
. | 匹配除 "\n" 之外的任何單個字符。要匹配包括 '\n' 在內的任何字符,請使用象 '[.\n]' 的模式。 |
\d | 匹配一個數字字符。等價於 [0-9]。 |
\D | 匹配一個非數字字符。等價於 [^0-9]。 |
\s | 匹配任何空白字符,包括空格、制表符、換頁符等等。等價於 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價於 [^ \f\n\r\t\v]。 |
\w | 匹配包括下划線的任何單詞字符。等價於'[A-Za-z0-9_]'。 |
\W | 匹配任何非單詞字符。等價於 '[^A-Za-z0-9_]'。 |
re.match與re.search的區別
re.match只匹配字符串的開始,如果字符串開始不符合正則表達式,則匹配失敗,函數返回None;而re.search匹配整個字符串,直到找到一個匹配。
Regular Expression Modifiers: Option Flags
Regular expression literals may include an optional modifier to control various aspects of matching. The modifiers are specified as an optional flag. You can provide multiple modifiers using exclusive OR (|), as shown previously and may be represented by one of these −
Modifier | Description |
---|---|
re.I | Performs case-insensitive matching. |
re.L | Interprets words according to the current locale. This interpretation affects the alphabetic group (\w and \W), as well as word boundary behavior (\b and \B). |
re.M | Makes $ match the end of a line (not just the end of the string) and makes ^ match the start of any line (not just the start of the string). |
re.S | Makes a period (dot) match any character, including a newline. |
re.U | Interprets letters according to the Unicode character set. This flag affects the behavior of \w, \W, \b, \B. |
re.X | Permits "cuter" regular expression syntax. It ignores whitespace (except inside a set [] or when escaped by a backslash) and treats unescaped # as a comment marker. |
幾個常見正則例子:
匹配手機號
phone_str = "hey my name is alex, and my phone number is 13651054607, please call me if you are pretty!" phone_str2 = "hey my name is alex, and my phone number is 18651054604, please call me if you are pretty!" m = re.search("(1)([358]\d{9})",phone_str2) if m: print(m.group())
匹配IP V4
ip_addr = "inet 192.168.60.223 netmask 0xffffff00 broadcast 192.168.60.255" m = re.search("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", ip_addr) print(m.group())
分組匹配地址
contactInfo = 'Oldboy School, Beijing Changping Shahe: 010-8343245' match = re.search(r'(\w+), (\w+): (\S+)', contactInfo) #分組 """ >>> match.group(1) 'Doe' >>> match.group(2) 'John' >>> match.group(3) '555-1212' """ match = re.search(r'(?P<last>\w+), (?P<first>\w+): (?P<phone>\S+)', contactInfo) """ >>> match.group('last') 'Doe' >>> match.group('first') 'John' >>> match.group('phone') '555-1212' """
匹配email
email = "alex.li@126.com http://www.oldboyedu.com" m = re.search(r"[0-9.a-z]{0,26}@[0-9.a-z]{0,20}.[0-9a-z]{0,8}", email) print(m.group())
json 和 pickle
用於序列化的兩個模塊
- json,用於字符串 和 python數據類型間進行轉換
- pickle,用於python特有的類型 和 python的數據類型間進行轉換
Json模塊提供了四個功能:dumps、dump、loads、load
pickle模塊提供了四個功能:dumps、dump、loads、load
其它常用模塊學習
http://www.cnblogs.com/wupeiqi/articles/4963027.html