Python之路,Day4
本節(jié)大綱
- 迭代器&生成器
- 裝飾器
- 基本裝飾器
- 多參數(shù)裝飾器
- 遞歸
- 算法基礎(chǔ):二分查找、二維數(shù)組轉(zhuǎn)換
- 正則表達(dá)式
- 常用模塊學(xué)習(xí)
- 作業(yè):計(jì)算器開(kāi)發(fā)
- 實(shí)現(xiàn)加減乘除及拓號(hào)優(yōu)先級(jí)解析
- 用戶輸入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等類似公式后,必須自己解析里面的(),+,-,*,/符號(hào)和公式,運(yùn)算后得出結(jié)果,結(jié)果必須與真實(shí)的計(jì)算器所得出的結(jié)果一致
迭代器&生成器
迭代器
迭代器是訪問(wèn)集合元素的一種方式。迭代器對(duì)象從集合的第一個(gè)元素開(kāi)始訪問(wèn),直到所有的元素被訪問(wèn)完結(jié)束。迭代器只能往前不會(huì)后退,不過(guò)這也沒(méi)什么,因?yàn)槿藗兒苌僭诘局型笸?。另外,迭代器的一大?yōu)點(diǎn)是不要求事先準(zhǔn)備好整個(gè)迭代過(guò)程中所有的元素。迭代器僅僅在迭代到某個(gè)元素時(shí)才計(jì)算該元素,而在這之前或之后,元素可以不存在或者被銷毀。這個(gè)特點(diǎn)使得它特別適合用于遍歷一些巨大的或是無(wú)限的集合,比如幾個(gè)G的文件
特點(diǎn):
- 訪問(wèn)者不需要關(guān)心迭代器內(nèi)部的結(jié)構(gòu),僅需通過(guò)next()方法不斷去取下一個(gè)內(nèi)容
- 不能隨機(jī)訪問(wèn)集合中的某個(gè)值 ,只能從頭到尾依次訪問(wèn)
- 訪問(wèn)到一半時(shí)不能往回退
- 便于循環(huán)比較大的數(shù)據(jù)集合,節(jié)省內(nèi)存
生成一個(gè)迭代器:
>>> 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
定義:一個(gè)函數(shù)調(diào)用時(shí)返回一個(gè)迭代器,那這個(gè)函數(shù)就叫做生成器(generator),如果函數(shù)中包含yield語(yǔ)法,那這個(gè)函數(shù)就會(huì)變成生成器
代碼:
def cash_out(amount):
while amount >0:
amount -= 1
yield 1
print("擦,又來(lái)取錢了。。。敗家子!")
ATM = cash_out(5)
print("取到錢 %s 萬(wàn)" % ATM.__next__())
print("花掉花掉!")
print("取到錢 %s 萬(wàn)" % ATM.__next__())
print("取到錢 %s 萬(wàn)" % ATM.__next__())
print("花掉花掉!")
print("取到錢 %s 萬(wàn)" % ATM.__next__())
print("取到錢 %s 萬(wàn)" % ATM.__next__())
print("取到錢 %s 萬(wàn)" % ATM.__next__()) #到這時(shí)錢就取沒(méi)了,再取就報(bào)錯(cuò)了
print("取到錢 %s 萬(wàn)" % ATM.__next__())
作用:
這個(gè)yield的主要效果呢,就是可以使函數(shù)中斷,并保存中斷狀態(tài),中斷后,代碼可以繼續(xù)往下執(zhí)行,過(guò)一段時(shí)間還可以再重新調(diào)用這個(gè)函數(shù),從上次yield的下一句開(kāi)始執(zhí)行。
另外,還可通過(guò)yield實(shí)現(xiàn)在單線程的情況下實(shí)現(xiàn)并發(fā)運(yùn)算的效果
import time
def consumer(name):
print("%s 準(zhǔn)備吃包子啦!" %name)
while True:
baozi = yield
print("包子[%s]來(lái)了,被[%s]吃了!" %(baozi,name))
def producer(name):
c = consumer('A')
c2 = consumer('B')
c.__next__()
c2.__next__()
print("老子開(kāi)始準(zhǔn)備做包子啦!")
for i in range(10):
time.sleep(1)
print("做了2個(gè)包子!")
c.send(i)
c2.send(i)
producer("alex")
裝飾器
直接 看銀角大王寫的文檔 http://www.rzrgm.cn/wupeiqi/articles/4980620.html
遞歸
特點(diǎn)
要求
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,以上就是典型的遞歸用法,在程序里自己調(diào)用自己。
算法基礎(chǔ)
#!_*_coding:utf-8_*_
array=[[col for col in range(5)] for row in range(5)] #初始化一個(gè)4*4數(shù)組
#array=[[col for col in 'abcde'] for row in range(5)]
for row in array: #旋轉(zhuǎn)前先看看數(shù)組長(zhǎng)啥樣
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 --')
冒泡排序
將一個(gè)不規(guī)則的數(shù)組按從小到大的順序進(jìn)行排序
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)時(shí)間頻度 一個(gè)算法執(zhí)行所耗費(fèi)的時(shí)間,從理論上是不能算出來(lái)的,必須上機(jī)運(yùn)行測(cè)試才能知道。但我們不可能也沒(méi)有必要對(duì)每個(gè)算法都上機(jī)測(cè)試,只需知道哪個(gè)算法花費(fèi)的時(shí)間多,哪個(gè)算法花費(fèi)的時(shí)間少就可以了。并且一個(gè)算法花費(fèi)的時(shí)間與算法中語(yǔ)句的執(zhí)行次數(shù)成正比例,哪個(gè)算法中語(yǔ)句執(zhí)行次數(shù)多,它花費(fèi)時(shí)間就多。一個(gè)算法中的語(yǔ)句執(zhí)行次數(shù)稱為語(yǔ)句頻度或時(shí)間頻度。記為T(n)。
而呈指數(shù)成長(zhǎng)(即輸入數(shù)據(jù)的數(shù)量依線性成長(zhǎng),所花的時(shí)間將會(huì)以指數(shù)成長(zhǎng))for (i=1; i<=n; i++) x++; for (i=1; i<=n; i++) for (j=1; j<=n; j++) x++;
第一個(gè)for循環(huán)的時(shí)間復(fù)雜度為Ο(n),第二個(gè)for循環(huán)的時(shí)間復(fù)雜度為Ο(n2),則整個(gè)算法的時(shí)間復(fù)雜度為Ο(n+n2)=Ο(n2)。
常數(shù)時(shí)間
若對(duì)于一個(gè)算法,
的上界與輸入大小無(wú)關(guān),則稱其具有常數(shù)時(shí)間,記作
時(shí)間。一個(gè)例子是訪問(wèn)數(shù)組中的單個(gè)元素,因?yàn)樵L問(wèn)它只需要一條指令。但是,找到無(wú)序數(shù)組中的最小元素則不是,因?yàn)檫@需要遍歷所有元素來(lái)找出最小值。這是一項(xiàng)線性時(shí)間的操作,或稱
時(shí)間。但如果預(yù)先知道元素的數(shù)量并假設(shè)數(shù)量保持不變,則該操作也可被稱為具有常數(shù)時(shí)間。
對(duì)數(shù)時(shí)間
若算法的T(n) = O(log n),則稱其具有對(duì)數(shù)時(shí)間
常見(jiàn)的具有對(duì)數(shù)時(shí)間的算法有二叉樹(shù)的相關(guān)操作和二分搜索。
對(duì)數(shù)時(shí)間的算法是非常有效的,因?yàn)槊吭黾右粋€(gè)輸入,其所需要的額外計(jì)算時(shí)間會(huì)變小。
遞歸地將字符串砍半并且輸出是這個(gè)類別函數(shù)的一個(gè)簡(jiǎn)單例子。它需要O(log n)的時(shí)間因?yàn)槊看屋敵鲋拔覀兌紝⒆址嘲搿?這意味著,如果我們想增加輸出的次數(shù),我們需要將字符串長(zhǎng)度加倍。
線性時(shí)間
如果一個(gè)算法的時(shí)間復(fù)雜度為O(n),則稱這個(gè)算法具有線性時(shí)間,或O(n)時(shí)間。非正式地說(shuō),這意味著對(duì)于足夠大的輸入,運(yùn)行時(shí)間增加的大小與輸入成線性關(guān)系。例如,一個(gè)計(jì)算列表所有元素的和的程序,需要的時(shí)間與列表的長(zhǎng)度成正比。
正則表達(dá)式
import re #導(dǎo)入模塊名
p = re.compile("^[0-9]") #生成要匹配的正則對(duì)象 , ^代表從開(kāi)頭匹配,[0-9]代表匹配0至9的任意一個(gè)數(shù)字, 所以這里的意思是對(duì)傳進(jìn)來(lái)的字符串進(jìn)行匹配,如果這個(gè)字符串的開(kāi)頭第一個(gè)字符是數(shù)字,就代表匹配上了
m = p.match('14534Abc') #按上面生成的正則對(duì)象 去匹配 字符串, 如果能匹配成功,這個(gè)m就會(huì)有值, 否則m為None
if m: #不為空代表匹配上了
print(m.group()) #m.group()返回匹配上的結(jié)果,此處為1,因?yàn)槠ヅ渖系氖?這個(gè)字符
else:
print("doesn't match.")
上面的第2 和第3行也可以合并成一行來(lái)寫:
m = p.match("^[0-9]",'14534Abc')
效果是一樣的,區(qū)別在于,第一種方式是提前對(duì)要匹配的格式進(jìn)行了編譯(對(duì)匹配公式進(jìn)行解析),這樣再去匹配的時(shí)候就不用在編譯匹配的格式,第2種簡(jiǎn)寫是每次匹配的時(shí)候 都 要進(jìn)行一次匹配公式的編譯,所以,如果你需要從一個(gè)5w行的文件中匹配出所有以數(shù)字開(kāi)頭的行,建議先把正則公式進(jìn)行編譯再匹配,這樣速度會(huì)快點(diǎn)。
匹配格式
| 模式 | 描述 |
|---|---|
| ^ | 匹配字符串的開(kāi)頭 |
| $ | 匹配字符串的末尾。 |
| . | 匹配任意字符,除了換行符,當(dāng)re.DOTALL標(biāo)記被指定時(shí),則可以匹配包括換行符的任意字符。 |
| [...] | 用來(lái)表示一組字符,單獨(dú)列出:[amk] 匹配 'a','m'或'k' |
| [^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
| re* | 匹配0個(gè)或多個(gè)的表達(dá)式。 |
| re+ | 匹配1個(gè)或多個(gè)的表達(dá)式。 |
| re? | 匹配0個(gè)或1個(gè)由前面的正則表達(dá)式定義的片段,非貪婪方式 |
| re{ n} | |
| re{ n,} | 精確匹配n個(gè)前面表達(dá)式。 |
| re{ n, m} | 匹配 n 到 m 次由前面的正則表達(dá)式定義的片段,貪婪方式 |
| a| b | 匹配a或b |
| (re) | G匹配括號(hào)內(nèi)的表達(dá)式,也表示一個(gè)組 |
| (?imx) | 正則表達(dá)式包含三種可選標(biāo)志:i, m, 或 x 。只影響括號(hào)中的區(qū)域。 |
| (?-imx) | 正則表達(dá)式關(guān)閉 i, m, 或 x 可選標(biāo)志。只影響括號(hào)中的區(qū)域。 |
| (?: re) | 類似 (...), 但是不表示一個(gè)組 |
| (?imx: re) | 在括號(hào)中使用i, m, 或 x 可選標(biāo)志 |
| (?-imx: re) | 在括號(hào)中不使用i, m, 或 x 可選標(biāo)志 |
| (?#...) | 注釋. |
| (?= re) | 前向肯定界定符。如果所含正則表達(dá)式,以 ... 表示,在當(dāng)前位置成功匹配時(shí)成功,否則失敗。但一旦所含表達(dá)式已經(jīng)嘗試,匹配引擎根本沒(méi)有提高;模式的剩余部分還要嘗試界定符的右邊。 |
| (?! re) | 前向否定界定符。與肯定界定符相反;當(dāng)所含表達(dá)式不能在字符串當(dāng)前位置匹配時(shí)成功 |
| (?> re) | 匹配的獨(dú)立模式,省去回溯。 |
| \w | 匹配字母數(shù)字 |
| \W | 匹配非字母數(shù)字 |
| \s | 匹配任意空白字符,等價(jià)于 [\t\n\r\f]. |
| \S | 匹配任意非空字符 |
| \d | 匹配任意數(shù)字,等價(jià)于 [0-9]. |
| \D | 匹配任意非數(shù)字 |
| \A | 匹配字符串開(kāi)始 |
| \Z | 匹配字符串結(jié)束,如果是存在換行,只匹配到換行前的結(jié)束字符串。c |
| \z | 匹配字符串結(jié)束 |
| \G | 匹配最后匹配完成的位置。 |
| \b | 匹配一個(gè)單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
| \B | 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
| \n, \t, 等. | 匹配一個(gè)換行符。匹配一個(gè)制表符。等 |
| \1...\9 | 匹配第n個(gè)分組的子表達(dá)式。 |
| \10 | 匹配第n個(gè)分組的子表達(dá)式,如果它經(jīng)匹配。否則指的是八進(jìn)制字符碼的表達(dá)式。 |
正則表達(dá)式常用5種操作
re.match(pattern, string) # 從頭匹配
re.search(pattern, string) # 匹配整個(gè)字符串,直到找到一個(gè)匹配
re.split() # 將匹配到的格式當(dāng)做分割點(diǎn)對(duì)字符串分割成列表
>>>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
正則表達(dá)式實(shí)例
字符匹配
| 實(shí)例 | 描述 |
|---|---|
| python | 匹配 "python". |
字符類
| 實(shí)例 | 描述 |
|---|---|
| [Pp]ython | 匹配 "Python" 或 "python" |
| rub[ye] | 匹配 "ruby" 或 "rube" |
| [aeiou] | 匹配中括號(hào)內(nèi)的任意一個(gè)字母 |
| [0-9] | 匹配任何數(shù)字。類似于 [0123456789] |
| [a-z] | 匹配任何小寫字母 |
| [A-Z] | 匹配任何大寫字母 |
| [a-zA-Z0-9] | 匹配任何字母及數(shù)字 |
| [^aeiou] | 除了aeiou字母以外的所有字符 |
| [^0-9] | 匹配除了數(shù)字外的字符 |
特殊字符類
| 實(shí)例 | 描述 |
|---|---|
| . | 匹配除 "\n" 之外的任何單個(gè)字符。要匹配包括 '\n' 在內(nèi)的任何字符,請(qǐng)使用象 '[.\n]' 的模式。 |
| \d | 匹配一個(gè)數(shù)字字符。等價(jià)于 [0-9]。 |
| \D | 匹配一個(gè)非數(shù)字字符。等價(jià)于 [^0-9]。 |
| \s | 匹配任何空白字符,包括空格、制表符、換頁(yè)符等等。等價(jià)于 [ \f\n\r\t\v]。 |
| \S | 匹配任何非空白字符。等價(jià)于 [^ \f\n\r\t\v]。 |
| \w | 匹配包括下劃線的任何單詞字符。等價(jià)于'[A-Za-z0-9_]'。 |
| \W | 匹配任何非單詞字符。等價(jià)于 '[^A-Za-z0-9_]'。 |
re.match與re.search的區(qū)別
re.match只匹配字符串的開(kāi)始,如果字符串開(kāi)始不符合正則表達(dá)式,則匹配失敗,函數(shù)返回None;而re.search匹配整個(gè)字符串,直到找到一個(gè)匹配。
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. |
幾個(gè)常見(jiàn)正則例子:
匹配手機(jī)號(hào)
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
用于序列化的兩個(gè)模塊
- json,用于字符串 和 python數(shù)據(jù)類型間進(jìn)行轉(zhuǎn)換
- pickle,用于python特有的類型 和 python的數(shù)據(jù)類型間進(jìn)行轉(zhuǎn)換
Json模塊提供了四個(gè)功能:dumps、dump、loads、load
pickle模塊提供了四個(gè)功能:dumps、dump、loads、load

其它常用模塊學(xué)習(xí)
http://www.rzrgm.cn/wupeiqi/articles/4963027.html

浙公網(wǎng)安備 33010602011771號(hào)