裝飾器、生成器、迭代器、及python中內置函數的使用
一、 裝飾器
1、 裝飾器的概述
(1)概述:裝飾器本質就是函數,主要用來裝飾其他函數,爲其他函數添加附加功能。
(2)使用裝飾器的原則
1)不能修改被裝飾的函數的源代碼
2)不能修改被裝飾的函數的調用方式
(3)裝飾器原理:函數即“變量”、高階函數、嵌套函數
2、使用裝飾器的原因
(1)傳統的多個函數模塊修改需要同時修改多個函數、如果函數過多,則修改不方便。
如下,如果想要在每個函數中開頭結尾分別輸入內容,則需要在每個函數開頭結尾加入需要輸出的內容。
def f1(): print("F1") def f2(): print("F2") ........................ def f100(): print("F100")
在開頭結尾分別加入輸出內容:
def f1(): print("head") print("F1") print("end") def f2(): print("head") print("F2") print("end") ........................ def f100(): print("head") print("F100") print("end")
(2)通過裝飾器可以在調用函數前或者調用函數後定義一些功能讓函數去執行。如果通過裝飾器去修改上面函數,只需要再寫一個裝飾器函數,在需要的函數前通過“@functionname”調用即可
通過裝飾器修改函數內容:
def outer(func): def inner(): print('log') ret = func() print('after') return ret return inner() @outer def f1(): print("F1") @outer def f2(): print("F2") @outer def f100(): print("F100")
3、使用裝飾器前注意事項
(1)如果定義兩個相同的函數,調用函數時,函數指針會指向最後定義的一個函數:
Author:Dayi123 def f1(): print(123) def f1(): print(456) f1() #打印第二個f1函數
(2)定義兩個函數,如果通過f2調用f1的函數名,調用的是整體f1
def f1(): print('123') def f2(xxx): xxx() f2(f1) # 調用的是整體f1
4、裝飾器的調用
(1)裝飾器的用法:@ + 函數名
(2)裝飾器的功能
1)自動執行outer函數並且將其下面的函數名f1當做參數傳遞
2)將outer函數的返回值,重新賦值給f1
裝飾器用法舉例:
def outer(func): def inner(): print("before") func() print('after') return inner() @outer def f1(): print("F1")
(3)裝飾器流程之返回值
一個完整的裝飾器如下:
def outer(func): def inner(): print('before') r = func() print('after') return r #裝飾器執行時沒有返回值,默認返回NOLL,此處將函數f1的執行結果賦 值給r,再返回給f1 return inner @outer def f1(): print("F1") return "hello" s = f1() print(s)
(4)裝飾器流程之參數
1)單個參數:
def outer(func): def inner(a): #當函數中有參數時,裝飾器中也應該加參數,以接受函數中的參數 print('before') r = func(a) print('after') returnr return inner @outer def f1(age): print(age) return "hello" s = f1('fafafa') print("返回值:",s)
2)兩個或兩個以上的參數:如果函數中存在兩個或者兩個以上的參數時,裝飾器中就需要用萬能參數接受函數傳遞的參數
def outer(func): def inner(*args, **kwargs): #當函數中存在兩個及以上參數時,裝飾器中應該用萬能參數去接受 函數傳遞的參數 print('before') r = func(*args, **kwargs) #此處應該也用萬能參數 print('after') return r return inner @outer def f1(age, name): print(age) print(name) return "hello" s = f1(24,"dayi")
(3)裝飾器應用案例——用戶管理程序:
LOGIN_USER = {"is_login":False} #此處用於標記用戶是否登錄 def outer(func): def inner(*args, **kwargs): if LOGIN_USER['is_login']: #如果用戶已經登錄,則執行下面語句 r = func() return r else: #如果用戶沒有登錄,則執行下面語句 print("請登錄") return inner @outer def oreder(): print("歡迎%s登錄" % LOGIN_USER['current_user']) @outer def changepwd(): print("歡迎%s登錄" % LOGIN_USER['current_user']) @outer def manager(): print("歡迎%s登錄" % LOGIN_USER['current_user']) def login(user, pwd): if user == "dayi123" and pwd == "dayi123": LOGIN_USER['is_login'] = True LOGIN_USER['current_user'] = user manager() def main(): while True: inp = input("1,後臺管理;2,登錄") if inp == '1': manager() elif inp == '2': username = input("請輸入用戶名") pwd = input("請輸入密碼") login(username, pwd) main()
5、用裝飾器實現不能的頁面採用不同的認證方式
import time user,passwd = 'dayi123','123456' def auth(auth_type): # 再加一層函數,用於接受auth_type print("auth func:",auth_type) def outer_wrapper(func):#接受裝飾的函數 def wrapper(*args, **kwargs): #接受裝飾函數的參數 print("wrapper func args:", *args, **kwargs) if auth_type== "local": #如果auth_type類型爲local,則從此處認證 username = input("Username:").strip() password = input("Password:").strip() if user== username and passwd == password: print("\033[32;1mUser has passed authentication\033[0m") res = func(*args,**kwargs) # from home print("---after authenticaion ") return res else: exit("\033[31;1mInvalid username or password\033[0m") # 如果auth_type類型爲ldap,則從此處認證 elif auth_type == "ldap": print("ldap auhciation.....................") return wrapper return outer_wrapper def index(): print("welcome to index page") @auth(auth_type="local") #home = wrapper() def home(): print("welcome to home page") return "fromhome" @auth(auth_type="ldap") def bbs(): print("welcome to bbs page") index() print(home())#wrapper() bbs()
三、生成器
1、列表生成式
a = [] for i in range(10): a.append(i*2) #相當於 print(a) a = [ i*2 for i in range(10)] print(a)
2、生成器
(1)生成器:一邊生成一遍計算的一種機制
(2)列表生成式和生成器:
#列表生成式 a = [ i*2 for iin range(100000000) ] #用列表生成器生成多個元素是,會一次生成 print(a) #列表生成器生成後會全部打印出來 print(a[100]) #由於已經生成放在了內存中,所以會打印出來 #生成器 b = ( i*2 for iin range(100000000) ) #列表生成器生成時沒有真正生成 print(b) #沒有真正生成,所以不能打印 # print(b[1000]) #沒有生成,所以不能切片 print() for i in b: #只有在調用時才生成 if i <20: print(i) continue else: break ret = b.__next__() #調用for循環後的下一個元素 print(ret) #打印 ret2 = b.__next__() print(ret2)
(3)用函數生成生成器
#斐波拉契數列用列表生成式寫出來 deffib(max): #10 n, a, b = 0, 0, 1 while n < max: #n<10 print(b) #執行此函數,則會把所有值一次性打印出來 a, b = b, a + b n = n + 1 # return '---done---' g =fib(60) #把斐波拉契數列中的print變爲yield,則這個函數變爲生成器: deffib(max): n, a, b = 0, 0, 1 while n < max: #n<10 yield b #變爲生成器後,則不會一次性打印出來,每調用一次,則打印一次 a, b = b, a + b n = n + 1 return '---done---' f=fib(10) #使用一次調用一次 print(f.__next__()) #每調用一次則打印一次,如果調用次數大於生成數量則會報錯 print(f.__next__()) print(f.__next__()) print(f.__next__())
注:此處的函數和生成器的區別:
生成器和函數的執行流程不一樣。函數是順序執行,遇到return語句或者最後一行函數語句就返回。而變成生成器的函數,在每次調用next()的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行。
(4)把函數改成生成器後,通過for循環來迭代:
def fib(max): #10 n, a, b = 0,0,1 while n <max: #n<10 yield b #yield保存了函數的終端狀態 a, b= b, a + b n = n + 1 return '---done---' #通過for循環來調用,拿不到返回值 for n in fib(19): #通過for循環來調用,但是拿不到返回值 print(n) #如果想要拿到返回值,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中 g =fib(60) whileTrue: try: #捕獲StopIteration錯誤,同時拿到返回值 x = next(g) #next()爲內置的方法,相當於__next__() print('g:', x) except StopIteration as e: print('Generator return value:',e.value) break
四、迭代器
1、可迭代對象(Interable):
(1)概述:可直接作用於for循環的對象統稱爲可迭代對象(主要包括集合數據類型,如列表、元組、字典、集合、字符串等和生成器類型)。
(2)判斷一個對象是否是可迭代對象的方法:isinstance()
使用之前需要導入模塊 :fromcollection import Iterable
判斷一個對象是否可循環:isinstance([].Iterable)
2、迭代器
(1)概述:迭代器是訪問集合元素的一種方式。迭代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完。迭代器僅僅在迭代到某個元素時才計算該元素,而在這之前或之後,元素可以不存在或者被銷燬。這使得它特別適合用於遍歷一些巨大的或是無限的集合。
(2)迭代器(Inerator):可以被next()函數調用並不斷返回下一個值的對象稱爲迭代器
(3)判斷一個對象是否是迭代器對象:isinstance()
用法:使用之前導入模塊:from collections import Iterator
判斷一個對象是否是迭代器:isinstance([].Iterator)
(3)特點:
1)訪問者不需要關心迭代器內部的結構,僅需通過next()方法不斷去取下一個內容
2)不能隨機訪問集合中的某個值 ,只能從頭到尾依次訪問
3)訪問到一半時不能往回退
4)便於循環比較大的數據集合,節省內存
5)和函數一起使用:可以使函數中斷並保存函數的中斷狀態
6)生成器都是Iterator對象,但list,dict,雖然是可迭代對象(Iterable),卻不是迭代器(Iterator),但list,dict,str等可迭代對象可以通過iter()函數變成迭代器
3、用法舉例:
def myrange(arg): start = 0 while True: if start >arg: return yield start start += 1 ret = myrange(10) for item in ret: #利用迭代器調用生成器生成的內容 print(item)
4、xrange舉例(xrange)將列表變成迭代器(Python2中)
>>>xrange(100000) xrange(100000) >>>a = xrange(1000000) #利用xrange生成一個列表 >>>a[1] 1
5、利用iter()將列表轉換成迭代器案例:
>>>a = range(10) >>>a = iter(a) #將生成的列表a轉化成迭代器 >>>print(a.__next__()) 0 >>>print(a.__next__()) 1 >>>print(a.__next__()) 2
五、 Python內置函數的應用舉例
1、abs()、bool()、all()、any()、bin()、oct()、hex()的使用
n = abs(-1) #abs() 用戶去絕對值 print(n) print(bool(0)) #對於bool(),只要裏面傳的是"0","None","""","[]","()"則返回False n1 = all([1,2,3,4]) #只要裏面有一個bool()中返回Falsh,則返回False,及所有爲真則爲真 print(n1) n2 = any(( 0,(),1)) #只要有一個爲真則爲真 print(n2) print(bin(5)) #將十進制轉化成二進制 print(oct(5)) #將十進制轉化成八進制 print(hex(15)) #將十進制轉換成十六進制
2、bytes()的使用
#bytes() #將需要的字符轉換成字節類型 s = "大易" n = bytes(s,encoding='utf-8') print(n) n1 = bytes(s,encoding='gbk') print(n1)#將字節轉化成字符串 new_str = str(bytes("大易",encoding='utf-8'),encoding='utf-8') print(new_str)
3、callable()、chr()、ord()、compile()、exec()、eval()的使用
#callable() #用來檢測傳的值是否可以被執行、被調用 #chr() #打印ascii嗎中數字對應的符號 r = chr(65) print(r) #ord() 打印ascii碼中字符對應的數字 n = ord("a") print(n) #compile() 將字符串編譯成Python代碼 s = "print(123)" r = compile(s,"<string>","exec") #exec爲編譯成機器碼模式,single爲單行模式,exec爲表達式模式 print(r) #exec()爲執行Python代碼或字符串 exec(r) #exec執行Python代碼 #eval() #將字符串轉化成表達式去執行,並拿到執行結果 m = "8*8" ret = eval(m) print(ret)
4、dir()、help()、divmod()、isinstance()的使用
#dir() 快速查看一個對象提供了那些功能(內置方法) print(dir(list)) #help() 查看幫助 help(list) #divmod() r = divmod(97, 10) #得到97除10的商和餘數,得到一個列表 print(r) print(r[0]) print(r[1]) #isinstance() 用來判斷對象是否是某個類的實例 s = [11,22,33] r = isinstance(s,list) #判斷s是不是列表的實例 print(r)
5、filter()的使用
#filter 用來做過濾,函數返回True,將元素添加到結果中 #filter用法 filter(函數, 可迭代的對象) def f2(a): if a>22: return True li = [11,22,33,44,55,66,77] ret = filter(f2, li) print(list(ret)) #只打印大於22的數字#用lambda去實現 li = [11,22,33,44,55] result = filter(lambda a: a > 33, li) print(list(result))
6、map()的使用
#map() 批量的數據做統一的操作,將函數的返回值添加到結果中 # 用法 map(函數,可迭代的對象(可以for循環的東西))#傳統的實現方法 li = [22,33,44,55] def f1(args): result = [] for i in args: result.append(100+i) return result r = f1(li) print(list(r)) #用map去實現 def f2(a): return a + 200 result = map(f2, li) print(list(result)) #用map+lambda去實現 result2 = map(lambda a: a + 300, li) print(list(result2)) #打印運算後的列表#也可以用for循環一個一個去打印 Result3 = map(lambda a: a*a, range(10)) #相當於列表生成式[ i*i for i in range(10)] # print(list(result3)) for i in result3: print(i)#reduce用法 import functools #導入模塊 res = functools.reduce( lambda x,y:x*y,range(1,10 )) #計算1到10的乘積 print(res)
Map用法2:
#僅在pyton2中使用,Python3中range(1,10)已變成迭代器 a = range(5,10) b = range(10,20) print map(None,a,b) #打印a、b生成的元組對,a或b中元素不夠時,會用None替代
輸出結果:[(5, 10), (6, 11), (7, 12), (8, 13), (9, 14), (None, 15), (None,16), (None, 17), (None, 18), (None, 19)]
7、globals()、locals()、len()、hash()的使用
#globals() #代表所有的全局變量,key-value格式 #locals() 代表所有的局部變量 NAME = "dayi123" def show(): a = 123 c = 456 print(locals()) print(globals()) show() #hash() s = "dayi" #生成hash值,一般用於字典的“key”保存 print(hash(s)) #len() 查看長度 s = "劉毅" print(len(s)) #計算字符串的長度 b = bytes(s, encoding="utf-8") #轉換成字節,計算字節的長度 print(len(b))
8、max(),sum(),min()、pow、sorted()、zip()、round()的使用
#max(),sum(),min()分別爲求最大值、求和、求最小值 r = ([11,22,33,1,40]) print(max(r)) #pow 求指數 w = pow(2, 10) print(w) #reverse() 翻轉,跟列表翻轉一樣 #round #四捨五入,取整數 n = round(1.8) print(n)n2 = round(1.234,2) #保留兩位小數 print(n2) #sorted() 排序 li = [21,22,4,55] print(sorted(li)) #作用同li.sort() 一樣 #zip 將列表合併到一起,將第一個元素合併成第一個元素,第二個元素合併成第二個元素 l1 = ["dayi",11,22,33] l2 = ["is",11,22,33] l3 = ["nb",11,22,33] haha = zip(l1, l2, l3) temp = list(haha)[0] print(temp) ret = ' '.join(temp) print(ret)