天天看點

Python(四)裝飾器、疊代器&生成器、re正規表達式、字元串格式化

本章内容:

  • 裝飾器
  • 疊代器 & 生成器
  • re 正規表達式
  • 字元串格式化

 裝飾器是一個很著名的設計模式,經常被用于有切面需求的場景,較為經典的有插入日志、性能測試、事務處理等。裝飾器是解決這類問題的絕佳設計,有了裝飾器,我們就可以抽離出大量函數中與函數功能本身無關的雷同代碼并繼續重用。概括的講,裝飾器的作用就是為已經存在的對象添加額外的功能。

先定義一個基本的裝飾器:

########## 基本裝飾器 ##########
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

@orter
def 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,jenny
This 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

@orter
def 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,jenny
This 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      
Python(四)裝飾器、疊代器&生成器、re正規表達式、字元串格式化

1、疊代器

  疊代器隻不過是一個實作疊代器協定的容器對象。

特點:

  1. 通路者不需要關心疊代器内部的結構,僅需通過next()方法不斷去取下一個内容
  2. 不能随機通路集合中的某個值 ,隻能從頭到尾依次通路
  3. 通路到一半時不能往回退
  4. 便于循環比較大的資料集合,節省記憶體
a = iter([1,2,3,4])
print a
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()


<listiterator object at 0x00000000023E9710>
1
2
3
4
Traceback (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() #關閉生成器

one
1
two
2
sr
3      

生成器的表達式:

a = [1,2,3]
b = [i+3 for i in a]
print b
print type(b)


ib = (i+3 for i in a)
print ib
print ib.next()
print ib.next()
print ib.next()


[4, 5, 6]
<type 'list'>
<generator object <genexpr> at 0x00000000023E8A20>
4
5
6      

正規表達式:

正規表達式是用來比對字元串非常強大的工具,在其他程式設計語言中同樣有正規表達式的概念。就其本質而言,正規表達式(或 RE)是一種小型的、高度專業化的程式設計語言,(在Python中)它内嵌在Python中,并通過 re 子產品實作。正規表達式模式被編譯成一系列的位元組碼,然後由用 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中
print(b.re)                  #re.compile('nick')      

兩種比對方式差別在于:第一種簡寫是每次比對的時候都要進行一次比對公式的編譯,第二種方式是提前對要比對的格式進行了編譯(對比對公式進行解析),這樣再去比對的時候就不用在編譯比對的格式。

比對規則:

 .      
  "." 比對任意字元(除了\n)      
  \      
  "\" 轉義字元      
  [...]      
  "[...]" 比對字元集      
<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         
  比對任何十進制數;它相當于類 [0-9]      
  \D      
  比對任何非數字字元;它相當于類 [^0-9]      
  \s      
  比對任何空白字元;它相當于類 [\t\n\r\f\v]      
  \S      
  比對任何非空白字元;它相當于類 [^\t\n\r\f\v]      
  \w      
  比對任何字母數字字元;它相當于類 [a-zA-Z0-9]      
  \W        
  比對任何非字母數字字元;它相當于類 [^a-zA-Z0-9]      
# \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次或者無限次      
  +      
   "+" 比對前一個字元1次或者無限次      
  ?      
    "?" 比對一個字元0次或者1次
   {m} {m,n}     {m} {m,n} 比對前一個字元m次或者m到n次
   *? +? ??     *? +? ?? 比對模式變為非貪婪(盡可能少比對字元串)
# "*" 比對前一個字元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)沒有比對上9
b = a.group()
print(b)
 
# {m} {m,n} 比對前一個字元m次或者m到n次
a = re.match(r"[\w]{6,10}@qq.com","[email protected]")
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)      
  ^        
   "^" 比對字元串開頭,多行模式中比對每一行的開頭      
   $      
   "$" 比對字元串結尾,多行模式中比對每一行的末尾      
   \A      
   \A 僅比對字元串開頭      
    \Z    \Z 僅比對字元串結尾
    \b    \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)      
 |      
  "|" 比對左右任意一個表達式      
  ab      
  (ab) 括号中表達式作為一個分組      
  \<number>      
  \<number> 引用編号為num的分組比對到的字元串      
  (?P<key>vlaue)      
  (?P<key>vlaue) 比對到一個字典,去vlaue也可做别名      
  (?P=name)      
  (?P=name) 引用别名為name的分組比對字元串      
# "|" 比對左右任意一個表達式
a = re.match(r"nick|jenny","jenny")
b = a.group()
print(b)
 
# (ab) 括号中表達式作為一個分組
a = re.match(r"[\w]{6,10}@(qq|163).com","[email protected]")
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      
  找到比對,傳回所有比對部分的清單      
   finditer
  傳回一個疊代器      
  sub   将字元串中比對正規表達式的部分替換為其他值
  split   根據比對分割字元串,傳回分割字元串組成的清單
######## 子產品方法介紹 #########
# 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 将字元串中比對正規表達式的部分替換為其他值
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', '']   #注意後邊空元素      
 group()      
  傳回被 RE 比對的字元串      
  groups()      
  傳回一個包含正規表達式中所有小組字元串的元組,從 1 到所含的小組号      
  groupdict()      
  傳回(?P<key>vlace)定義的字典      
  start()      
  傳回比對開始的位置      
  end()      
  傳回比對結束的位置      
  span()      
  傳回一個元組包含比對 (開始,結束) 的索引位置      
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 re
a = "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      
  使比對對大小寫不敏感      
  re.L      
  做本地化識别(locale-aware)比對      
  re.M      
  多行比對,影響 ^ 和 $      
  re.S        
  使 . 比對包括換行在内的所有字元      
  re.U      
  根據Unicode字元集解析字元。這個标志影響 \w, \W, \b, \B.      
  re.X      
  注釋,會影響空格(無效了)      
#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:

# 比對 email
email = '[email protected]'
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中切換
常用格式化:
 
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)