Python之路,Day4


本節大綱

  1. 迭代器&生成器
  2. 裝飾器 
    1. 基本裝飾器
    2. 多參數裝飾器
  3. 遞歸
  4. 算法基礎:二分查找、二維數組轉換
  5. 正則表達式
  6. 常用模塊學習
  7. 作業:計算器開發
    1. 實現加減乘除及拓號優先級解析
    2. 用戶輸入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等類似公式后,必須自己解析里面的(),+,-,*,/符號和公式,運算后得出結果,結果必須與真實的計算器所得出的結果一致

迭代器&生成器

 

迭代器

迭代器是訪問集合元素的一種方式。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。迭代器只能往前不會后退,不過這也沒什么,因為人們很少在迭代途中往后退。另外,迭代器的一大優點是不要求事先准備好整個迭代過程中所有的元素。迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之后,元素可以不存在或者被銷毀。這個特點使得它特別適合用於遍歷一些巨大的或是無限的集合,比如幾個G的文件

特點:

  1. 訪問者不需要關心迭代器內部的結構,僅需通過next()方法不斷去取下一個內容
  2. 不能隨機訪問集合中的某個值 ,只能從頭到尾依次訪問
  3. 訪問到一半時不能往回退
  4. 便於循環比較大的數據集合,節省內存

生成一個迭代器:

>>> 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  

 

遞歸

特點

遞歸算法是一種直接或者間接地調用自身算法的過程。在計算機編寫程序中,遞歸算法對解決一大類問題是十分有效的,它往往使算法的描述簡潔而且易於理解。
遞歸算法解決問題的特點:
(1) 遞歸就是在過程或函數里調用自身。
(2) 在使用遞歸策略時,必須有一個明確的遞歸結束條件,稱為遞歸出口。
(3) 遞歸算法解題通常顯得很簡潔,但遞歸算法解題的運行效率較低。所以一般不提倡用遞歸算法設計程序。
(4) 在 遞歸調用的過程當中系統為每一層的返回點、局部量等開辟了棧來存儲。遞歸次數過多容易造成 棧溢出等。所以一般不提倡用遞歸算法設計程序。

要求

遞歸算法所體現的“重復”一般有三個要求:
一是每次調用在規模上都有所縮小(通常是減半);
二是相鄰兩次重復之間有緊密的聯系,前一次要為后一次做准備(通常前一次的輸出就作為后一次的輸入);
三是在問題的規模極小時必須用直接給出解答而不再進行 遞歸調用,因而每次遞歸調用都是有條件的(以規模未達到直接解答的大小為條件),無條件遞歸調用將會成為死循環而不能正常結束。
 
實現
1. 通過遞歸實現2分查找
  現有列表 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], 要求爾等 用最快的方式 找出 23 。 請Low B, Low 2B ,Low 3B 三個同學來回答這個問題。 
  Low B: 這個很簡單,直接用 if 41 in primes:print("found it!") , 話音未落就被老師打了,讓你自己實現,不是讓你用現成提供的功能, Low B於是說,那只能從頭開始一個個數了,然后Low B被 開除了。。。
  Low 2B: 因為這個列表是有序的, 我可以把列表從中截取一半,大概如下:
    p1 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,41]
    p2 = [ 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
    然后看p1[-1]也就是41是否比23大, 如果比23大就代表23肯定在p1里面,否則那就肯定在p2里面。現在我們知道23比41小,所以23肯定在p1里,但p1里依然有很多元素, 怎么找到23呢?很簡單,依然按上一次的方法,把p1分成2部分,如下:
    p1_a = [2, 3, 5, 7, 11, 13,17]
    p1_b = [19, 23, 29, 31, 37,41]
    然后我們發現,23 比p1_a最后一個值 17 大,那代表23肯定在p1_b中, p1_b中依然有很多元素,那就再按之前的方法繼續分半,最終用不了幾次,肯定就把23找出來了!
    說完,Low 2B滿有成就感的甩了下頭上的頭皮屑。
  老師:很好,確實較Low B的方案強很多。 然后轉頭問Low 3B ,你有更好的想法 么? 
      Low 3B: 啊。。。噢 ,我。。。我跟Low 2B的想法一樣,結果被他說了。
      老師:噢,那你幫我把代碼寫出來吧。 
      Low 3B此時冷汗直冒,因為他根本沒思路,但還是硬着頭皮去寫了。。。。雖然自己沒思路,但是會谷歌呀,三個小時過去了,終於憋出了以下代碼:
 
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,以上就是典型的遞歸用法,在程序里自己調用自己。

 

算法基礎 

要求:生成一個4*4的2維數組並將其順時針旋轉90度
#!_*_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)。
(2)時間復雜度 在剛才提到的時間頻度中,n稱為問題的規模,當n不斷變化時,時間頻度T(n)也會不斷變化。但有時我們想知道它變化時呈現什么規律。為此,我們引入時間復雜度概念。 一般情況下,算法中基本操作重復執行的次數是問題規模n的某個函數,用T(n)表示,若有某個輔助函數f(n),使得當n趨近於無窮大時, T(n)/f(n)的極限值為不等於零的常數,則稱f(n)是T(n)的同數量級函數。記作 T(n)=O(f(n)),O(f(n)) 為算法的漸進時間復雜度,簡稱時間復雜度。
 
指數時間
指的是一個問題求解所需要的 計算時間 m( n),依輸入數據的大小 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(1)時間。一個例子是訪問數組中的單個元素,因為訪問它只需要一條指令。但是,找到無序數組中的最小元素則不是,因為這需要遍歷所有元素來找出最小值。這是一項線性時間的操作,或稱O(n)時間。但如果預先知道元素的數量並假設數量保持不變,則該操作也可被稱為具有常數時間。

 

對數時間 

若算法的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 

  

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM