本章內容:
裝飾器
迭代器 & 產生器
re Regex
字串格式化
裝飾器
裝飾器是一個很著名的設計模式,經常被用於有切面需求的情境,較為經典的有插入日誌、效能測試、交易處理等。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量函數中與函數功能本身無關的雷同代碼並繼續重用。概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能。
先定義一個基本的裝飾器:
########## 基本裝飾器 ##########def orter(func): #定義裝飾器 def inner(): print("This is inner before.") s = func() #調用原傳入參數函數執行 print("This is inner after.") return s #return原函數傳回值 return inner #將inner函數return給name函數 @orter #調用裝飾器(將函數name當參數傳入orter裝飾器)def name(): print("This is name.") return True #name原函數return True ret = name()print(ret) 輸出結果:This is inner before.This is name.This is inner after.True
給裝飾器傳參數:
############ 裝飾器傳參數 ###########def orter(func): def inner(a,b): #接收傳入的2個參數 print("This is inner before.") s = func(a,b) #接收傳入的原函數2個參數 print("This is inner after.") return s return inner @orterdef name(a,b): #接收傳入的2個參數,並name整體函數當參數傳入orter裝飾器 print("This is name.%s,%s"%(a,b)) return True ret = name('nick','jenny') #傳入2個參數print(ret) 輸出結果:This is inner before.This is name.nick,jennyThis is inner after.True
給裝飾器傳萬能參數:
########## 萬能參數裝飾器 ########## def orter(func): def inner(*args,**kwargs): #萬能參數接收多個參數 print("This is inner before.") s = func(*args,**kwargs) #萬能參數接收多個參數 print("This is inner after.") return s return inner @orterdef name(a,b,c,k1='nick'): #接受傳入的多個參數 print("This is name.%s,%s"%(a,b)) return True ret = name('nick','jenny','car')print(ret) 輸出結果:This is inner before.This is name.nick,jennyThis is inner after.True
一個函數應用多個裝飾器方法:
########### 一個函數應用多個裝飾器 ######### def orter(func): def inner(*args,**kwargs): print("This is inner one before.") print("This is inner one before angin.") s = func(*args,**kwargs) print("This is inner one after.") print("This is inner one after angin.") return s return inner def orter_2(func): def inner(*args,**kwargs): print("This is inner two before.") print("This is inner two before angin.") s = func(*args,**kwargs) print("This is inner two after.") print("This is inner two after angin.") return s return inner @orter #將以下函數整體當參數傳入orter裝飾器 @orter_2 #將以下函數當參數傳入orter_2裝飾器 def name(a,b,c,k1='nick'): print("This is name.%s and %s."%(a,b)) return True ret = name('nick','jenny','car')print(ret) 輸出結果:This is inner one before.This is inner one before angin.This is inner two before.This is inner two before angin.This is name.nick and jenny.This is inner two after.This is inner two after angin.This is inner one after.This is inner one after angin.True
迭代器 & 產生器
1、迭代器
迭代器只不過是一個實現迭代器協議的容器物件。
特點:
訪問者不需要關心迭代器內部的結構,僅需通過next()方法不斷去取下一個內容
不能隨機訪問集合中的某個值 ,只能從頭到尾依次訪問
訪問到一半時不能往回退
便於迴圈比較大的資料集合,節省記憶體
a = iter([1,2,3,4])print aprint a.next()print a.next()print a.next()print a.next()print a.next() <listiterator object at 0x00000000023E9710>1234Traceback (most recent call last): File "D:/python/untitled4/test.py", line 23, in <module> print a.next()StopIteration
2、產生器
一個函數調用時返回一個迭代器,那這個函數就叫做產生器(generator);如果函數中包含yield文法,那這個函數就會變成產生器。
def xran(): print ("one") yield 1 print "two" yield 2 print "sr" yield 3 ret = xran()#print ret #<generator object xran at 0x00000000022D8AB0> result = ret.next()print result result = ret.next()print result result = ret.next()print result # ret.next() #迴圈完畢拋出異常# ret.close() #關閉產生器 one1two2sr3
產生器的運算式:
a = [1,2,3]b = [i+3 for i in a]print bprint type(b) ib = (i+3 for i in a)print ibprint ib.next()print ib.next()print ib.next() [4, 5, 6]<type 'list'><generator object <genexpr> at 0x00000000023E8A20>456
Regex:
Regex是用來匹配字串非常強大的工具,在其他程式設計語言中同樣有Regex的概念。就其本質而言,Regex(或 RE)是一種小型的、高度專業化的程式設計語言,(在Python中)它內嵌在Python中,並通過 re 模組實現。Regex模式被編譯成一系列的位元組碼,然後由用 C 編寫的匹配引擎執行。
#匯入 re 模組import re s = 'nick jenny nice' # 匹配方式(一)b = re.match(r'nick',s)q = b.group()print(q) # 匹配方式(二)# 產生Pattern對象執行個體,r表示匹配源字串a = re.compile(r'nick')print(type(a)) #<class '_sre.SRE_Pattern'> b = a.match(s)print(b) #<_sre.SRE_Match object; span=(0, 4), match='nick'> q = b.group()print(q) #被匹配的字串放在string中print(b.string) #nick jenny nice#要匹配的字串放在re中
兩種匹配方式區別在於:第一種簡寫是每次匹配的時候都要進行一次匹配公式的編譯,第二種方式是提前對要匹配的格式進行了編譯(對匹配公式進行解析),這樣再去匹配的時候就不用在編譯匹配的格式。
匹配規則:
<br># "." 匹配任一字元(除了\n)a = re.match(r".","95nick")b = a.group()print(b) # [...] 匹配字元集a = re.match(r"[a-zA-Z0-9]","123Nick")b = a.group()print(b)
# \d \D 匹配數字/非數字a = re.match(r"\D","nick")b = a.group()print(b) # \s \S 匹配空白/非空白字元a = re.match(r"\s"," ")b = a.group()print(b) # \w \W 匹配單詞字元[a-zA-Z0-9]/非單詞字元a = re.match(r"\w","123Nick")b = a.group()print(b)a = re.match(r"\W","+-*/")b = a.group()print(b)
# "*" 匹配前一個字元0次或者無限次a = re.match(r"[A-Z][a-z]*","Aaaaaa123") #可以只匹配A,123不會匹配上b = a.group()print(b) # “+” 匹配前一個字元1次或者無限次a = re.match(r"[_a-zA-Z]+","nick")b = a.group()print(b) # “?” 匹配一個字元0次或者1次a = re.match(r"[0-8]?[0-9]","95") #(0-8)沒有匹配上9b = a.group()print(b) # {m} {m,n} 匹配前一個字元m次或者m到n次a = re.match(r"[\w]{6,10}@qq.com","630571017@qq.com")b = a.group()print(b) # *? +? ?? 匹配模式變為非貪婪(儘可能少匹配字串)a = re.match(r"[0-9][a-z]*?","9nick")b = a.group()print(b)a = re.match(r"[0-9][a-z]+?","9nick")b = a.group()print(b)
# "^" 匹配字串開頭,多行模式中匹配每一行的開頭。li = "nick\nnjenny\nsuo"a = re.search("^s.*",li,re.M)b = a.group()print(b) # "$" 匹配字串結尾,多行模式中匹配每一行的末尾。li = "nick\njenny\nnick"a = re.search(".*y$",li,re.M)b = a.group()print(b) # \A 僅匹配字串開頭li = "nickjennyk"a = re.findall(r"\Anick",li)print(a) # \Z 僅匹配字串結尾li = "nickjennyk"a = re.findall(r"nick\Z",li)print(a) # \b 匹配一個單詞邊界,也就是指單詞和空格間的位置a = re.search(r"\bnick\b","jenny nick car")b = a.group()print(b)
# "|" 匹配左右任意一個運算式a = re.match(r"nick|jenny","jenny")b = a.group()print(b) # (ab) 括弧中運算式作為一個分組a = re.match(r"[\w]{6,10}@(qq|163).com","630571017@qq.com")b = a.group()print(b) # \<number> 引用編號為num的分組匹配到的字串a = re.match(r"<([\w]+>)[\w]+</\1","<book>nick</book>")b = a.group()print(b) # (?P<key>vlace) 匹配輸出字典li = 'nick jenny nnnk'a = re.match("(?P<k1>n)(?P<k2>\w+).*(?P<k3>n\w+)",li)print(a.groupdict())輸出結果:{'k2': 'ick', 'k1': 'n', 'k3': 'nk'} # (?P<name>) 分組起一個別名# (?P=name) 引用別名為name的分組匹配字串a = re.match(r"<(?P<jenny>[\w]+>)[\w]+</(?P=jenny)","<book>nick</book>")b = a.group()print(b)
模組方法介紹
######## 模組方法介紹 ########## match 從頭匹配 # search 匹配整個字串,直到找到一個匹配 # findall 找到匹配,返回所有匹配部分的列表# findall 加括弧li = 'nick jenny nick car girl' r = re.findall('n\w+',li)print(r)#輸出結果:['nick', 'nny', 'nick']r = re.findall('(n\w+)',li)print(r)#輸出結果:['nick', 'nny', 'nick']r = re.findall('n(\w+)',li)print(r)#輸出結果:['ick', 'ny', 'ick']r = re.findall('(n)(\w+)(k)',li)print(r)#輸出結果:[('n', 'ic', 'k'), ('n', 'ic', 'k')]r = re.findall('(n)((\w+)(c))(k)',li)print(r)#輸出結果:[('n', 'ic', 'i', 'c', 'k'), ('n', 'ic', 'i', 'c', 'k')] # finditer 返回一個迭代器,和findall一樣li = 'nick jenny nnnk'a = re.finditer(r'n\w+',li)for i in a: print(i.group()) # sub 將字串中匹配Regex的部分替換為其他值li = 'This is 95'a = re.sub(r"\d+","100",li)print(a) li = "nick njenny ncar ngirl"a = re.compile(r"\bn")b = a.sub('cool',li,3) #後邊參數替換幾次print(b) #輸出結果:#coolick cooljenny coolcar ngirl # split 根據匹配分割字串,返回分割字串組成的列表li = 'nick,suo jenny:nice car'a = re.split(r":| |,",li) # 或|,分割 :, 空白符print(a) li = 'nick1jenny2car3girl5'a = re.compile(r"\d")b = a.split(li)print(b) #輸出結果:#['nick', 'jenny', 'car', 'girl', ''] #注意後邊空元素
li = 'nick jenny nnnk' a = re.match("n\w+",li)print(a.group()) a = re.match("(n)(\w+)",li)print(a.groups()) a = re.match("(?P<k1>n)(?P<k2>\w+).*(?P<k3>n\w+)",li)print(a.groupdict()) -----------------------------------------------import rea = "123abc456" re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0) #123abc456,返回整體 re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1) #123 re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2) #abc re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3) #456 group(1) 列出第一個括弧匹配部分,group(2) 列出第二個括弧匹配部分,group(3)列出第三個括弧匹配部分。 -----------------------------------------------
#re.I 使匹配對大小寫不敏感
a = re.search(r"nick","NIck",re.I)
print(a.group())
#re.L 做本地化識別(locale-aware)匹配
#re.U 根據Unicode字元集解析字元。這個標誌影響 \w, \W, \b, \B.
#re.S:.將會匹配分行符號,預設.逗號不會匹配分行符號
a = re.findall(r".","nick\njenny",re.S)
print(a)
輸出結果:
['n', 'i', 'c', 'k', '\n', 'j', 'e', 'n', 'n', 'y']
#re.M:^$標誌將會匹配每一行,預設^只會匹配符合正則的第一行;預設$只會匹配符合正則的末行
n = """12 drummers drumming,
11 pipers piping, 10 lords a-leaping"""
p = re.compile("^\d+")
p_multi = re.compile("^\d+",re.M)
print(re.findall(p,n))
print(re.findall(p_multi,n))
常見正則列子:
匹配手機號:
# 匹配手機號phone_num = '13001000000'a = re.compile(r"^1[\d+]{10}")b = a.match(phone_num)print(b.group())
匹配IPv4:
# 匹配IP地址ip = '192.168.1.1'a = re.compile(r"(((1?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))\.){3}((1?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))$")b = a.search(ip)print(b)
匹配email:
# 匹配 emailemail = '630571017@qq.com'a = re.compile(r"(.*){0,26}@(\w+){0,20}.(\w+){0,8}")b = a.search(email)print(b.group())
字串格式化:
1、百分比符號方式
%[(name)][flags][width].[precision]typecode
(name) 可選,用於選擇指定的key
flags 可選,可供選擇的值有:width 可選,佔有寬度
+ 靠右對齊;正數前加正好,負數前加負號;
- 靠左對齊;正數前無符號,負數前加負號;
空格 靠右對齊;正數前加空格,負數前加負號;
0 靠右對齊;正數前無符號,負數前加負號;用0填充空白處
.precision 可選,小數點後保留的位元
typecode 必選
s,擷取傳入對象的__str__方法的傳回值,並將其格式化到指定位置
r,擷取傳入對象的__repr__方法的傳回值,並將其格式化到指定位置
c,整數:將數字轉換成其unicode對應的值,10進位範圍為 0 <= i <= 1114111(py27則只支援0-255);字元:將字元添加到指定位置
o,將整數轉換成 八 進位表示,並將其格式化到指定位置
x,將整數轉換成十六進位表示,並將其格式化到指定位置
d,將整數、浮點數轉換成 十 進位表示,並將其格式化到指定位置
e,將整數、浮點數轉換成科學計數法,並將其格式化到指定位置(小寫e)
E,將整數、浮點數轉換成科學計數法,並將其格式化到指定位置(大寫E)
f, 將整數、浮點數轉換成浮點數表示,並將其格式化到指定位置(預設保留小數點後6位)
F,同上
g,自動調整將整數、浮點數轉換成 浮點型或科學計數法表示(超過6位元用科學計數法),並將其格式化到指定位置(如果是科學計數則是e;)
G,自動調整將整數、浮點數轉換成 浮點型或科學計數法表示(超過6位元用科學計數法),並將其格式化到指定位置(如果是科學計數則是E;)
%,當字串中存在格式化標誌時,需要用 %%表示一個百分比符號
常用格式化: tpl = "i am %s" % "nick" tpl = "i am %s age %d" % ("nick", 18) tpl = "i am %(name)s age %(age)d" % {"name": "nick", "age": 18} tpl = "percent %.2f" % 99.97623 tpl = "i am %(pp).2f" % {"pp": 123.425556, } tpl = "i am %.2f %%" % {"pp": 123.425556, }
2、Format方式
[[fill]align][sign][#][0][width][,][.precision][type]
fill 【可選】空白處填充的字元
align 【可選】對齊(需配合width使用)
<,內容靠左對齊
>,內容靠右對齊(預設)
=,內容靠右對齊,將符號放置在填充字元的左側,且只對數字類型有效。 即使:符號+填充物+數字
^,內容置中
sign 【可選】有無符號數字
+,正號加正,負號加負;
-,正號不變,負號加負;
空格 ,正號空格,負號加負;
# 【可選】對於二進位、八進位、十六進位,如果加上#,會顯示 0b/0o/0x,否則不顯示
, 【可選】為數字添加分隔字元,如:1,000,000
width 【可選】格式化位所佔寬度
.precision 【可選】小數位保留精度
type 【可選】格式化類型
傳入” 字串類型 “的參數
傳入“ 整數類型 ”的參數
傳入“ 浮點型或小數類型 ”的參數
s,格式化字串類型資料
空白,未指定類型,則預設是None,同s
b,將10進位整數自動轉換成2進位表示然後格式化
c,將10進位整數自動轉換為其對應的unicode字元
d,十進位整數
o,將10進位整數自動轉換成8進位表示然後格式化;
x,將10進位整數自動轉換成16進位表示然後格式化(小寫x)
X,將10進位整數自動轉換成16進位表示然後格式化(大寫X)
e, 轉換為科學計數法(小寫e)表示,然後格式化;
E, 轉換為科學計數法(大寫E)表示,然後格式化;
f , 轉換為浮點型(預設小數點後保留6位)表示,然後格式化;
F, 轉換為浮點型(預設小數點後保留6位)表示,然後格式化;
g, 自動在e和f中切換
G, 自動在E和F中切換
%,顯示百分比(預設顯示小數點後6位)
常用格式化: tpl = "i am {}, age {}, {}".format("nick", 18, 'jenny') tpl = "i am {}, age {}, {}".format(*["nick", 18, 'jenny']) tpl = "i am {0}, age {1}, really {0}".format("nick", 18) tpl = "i am {0}, age {1}, really {0}".format(*["nick", 18]) tpl = "i am {name}, age {age}, really {name}".format(name="nick", age=18) tpl = "i am {name}, age {age}, really {name}".format(**{"name": "nick", "age": 18}) tpl = "i am {0[0]}, age {0[1]}, really {0[2]}".format([1, 2, 3], [11, 22, 33]) tpl = "i am {:s}, age {:d}, money {:f}".format("nick", 18, 88888.1) tpl = "i am {:s}, age {:d}, money {:0.2f}".format("nick", 18, 88888.111111111111) tpl = "i am {:s}, age {:d}".format(*["nick", 18]) tpl = "i am {name:s}, age {age:d}".format(name="nick", age=18) tpl = "i am {name:s}, age {age:d}".format(**{"name": "nick", "age": 18}) tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2) tpl = "numbers: {0:b},{0:o},{0:d},{0:x},{0:X}, {0:%}".format(15) tpl = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15)