python基礎(四)
阿新 • • 發佈:2018-11-05
site iterator list 就是 ati top 登錄認證 password 增加
內容摘要:本文主要是介紹閉包,裝飾器,裝飾器的應用與進階,叠代器與生成器,列表推導式以及生成器表達式內容。
1.閉包
‘‘‘ 整體說明: 01 動態參數:萬能參數,*args **kwargs (1)在函數定義時:* ** 代表聚合 (2)在函數調用時:* ** 代表打散 02 函數名的運用 (1)函數名可以作為變量。 (2)函數名可以作為函數的參數。 (3)函數名可以作為容器類類型的元素。(容器類型的數據包括字典、集合、列表(有序)、元素) (4)函數名可以作為函數的返回值。 03 閉包 (1)閉包是嵌套在函數中的。 (2)閉包是內層函數對外層函數的變量(非全局變量)的引用(改變)。 (3)閉包需要將其作為一個對象返回,而且必須逐層返回直至最外層的函數的返回值。 (4)閉包的作用:python遇到閉包,產生一個空間,這個空間不會隨著函數的結束而消失。(普通的非閉包的函數,變量的空間會隨著函數的結束而消失)‘‘‘ # 01 動態參數:萬能參數,*args **kwargs,在函數的定義時:* ** 代表聚合。 def func(*args, **kwargs): print(args) # (1, 2, 3, ‘alex‘) print(kwargs) # {‘name‘: ‘太白‘, ‘age‘: 25} func(1, 2, 3, ‘alex‘, name=‘太白‘, age=25) # 02 動態參數:萬能參數,*args **kwargs,在函數的調用時:* ** 代表打散 # *的使用 def func(*args, **kwargs): print(args) # (1, 2, 3, ‘alex‘, ‘太白‘) print(kwargs) # {} func(*[1, 2, 3, ], *[‘alex‘, ‘太白‘]) # **的使用 def func(*args, **kwargs): print(args) # () print(kwargs) # {‘name‘: ‘alex‘, ‘age‘: 73} func(**{‘name‘: ‘alex‘, ‘age‘: 73}) # func(**{1: ‘alex‘, ‘age‘: 73}) # 會報錯,因為關鍵字要求必須是字符串 # 03 函數名的應用# (1) 函數名可以作為變量 def func1(): print(1111) ret = func1 ret() 輸出結果:1111 # (2) 函數名可以作為函數的參數 def func2(): print(666) def func3(x): x() func3(func2) # 輸出結果:6666 # (3) 函數名可以作為容器類的元素 def func1(): print(666) def func2(): print(777) def func3(): print(888) l1 = [func1, func2, func3] for i in l1: i() # 輸出結果: 666 777 888 # (4) 函數名可以作為函數的返回值 def func1(): print(666) def func2(x): print(888) return x ret = func2(func1) # 遇到賦值預算先計算賦值運算作出的內容,本賦值是先執行func2函數, 並且將func1作為返回值返回給我ret ret() # 由於func1的函數名賦值給ret,所以ret具有func1作為函數的所有特性,即函數名()-是函數的調用者,所以執行func1函數 # 輸出結果:888 666 # 04 閉包 # (1) 閉包的舉例: # 以下是閉包 def wrapper(): name = ‘太白‘ def inner(): print(name) return inner # 以下是閉包:外層函數的變量定義相當於name = n1,是個局部變量所以滿足條件,因此是閉包。 def wrapper(name): def inner(): print(name) return inner n1 = ‘wusir‘ wrapper(n1) # 以下不是閉包:因為內層函數調用的變量是全局變量,而不是外層函數的局部變量,未滿足條件所以不是。 name = ‘alex‘ def wrapper(): def inner(): print(name) return inner # (2)閉包的作用 # 非閉包函數 隨著函數的結束臨時空間關閉,即變量的賦值會清空 def func1(s1): n = 1 n += s1 print(n) func1(5) func1(5) func1(5) func1(5) # 輸出結果: 6 6 6 6 # 閉包的機制:python遇到閉包,產生一個空間,這個空間不會隨著函數的結束而消失。 def wrapper(s1): n = 1 def inner(): nonlocal n # 在局部作用域中,對父級作用域(或者更外層作用域非全局作用域)的變量進行引用和修改,並且引用的哪層,從那層及以下此變量全部發生改變。 n += s1 print(n) return inner ret = wrapper(5) ret() ret() ret() ret() # 輸出結果:6 11 16 21
2.裝飾器
‘‘‘ 整體說明: 01 裝飾器說明 (1) 裝飾器的本質是閉包。 (2) 裝飾器是在不改變原函數的內部函數體以及調用方式(也包括調用次數)的情況下,給函數增加了額外的功能:比如登錄、註冊、打印日誌、函數效率等等。 02 標準裝飾器:手寫的標準裝飾器總共分5步。 ‘‘‘ # 01 標準裝飾器 def wrapper(f): def inner(*args, **kwargs): print(‘執行之前‘, 555) # 在執行前可以編寫新增的功能代碼,比如登錄驗證、註冊、打印日誌等。 ret = f(*args, **kwargs) # 該處是裝飾器核心,用於調用函數使用 print(‘執行之後‘, 666) # 在執行前可以編寫新增的功能代碼,比如登錄驗證、註冊、打印日誌等。 return ret return inner # 02 裝飾器的使用方式 # 0201 初級的引用方式(未優化版本) # 引用時間模塊 import time def func1(): time.sleep(0.6) print(‘來了,老弟‘) def func2(): time.sleep(0.6) print(‘來le‘) def func3(): time.sleep(0.6) print(‘來‘) # 定義一個測量函數執行執行效率的裝飾器 def func1(): time.sleep(0.6) print(‘來了,老弟‘) def timmer(f): # f = func1 函數名的內存地址 def inner(): start_time = time.time() f() end_time = time.time() print(‘此函數的執行時間是%s‘ % (end_time-start_time)) return inner func1 = timmer(func1) # 首先執行賦值運算,將返回值inner函數名的內存地址賦值給新變量func1,新變量func1具有inner作為函數名的所有特性 func1() # inner() ‘‘‘ 以上函數具體執行過程說明: 1.先計算賦值運算左側的:timmer(func1) 2.執行timmer函數,並且將func1傳遞給f 3.inner函數不執行,將inner函數名返回給timmer(func1) 4.在內存中重新創建一個變量叫做func1,此時func1 = inner 5.執行inner()執行inner函數,執行f() ‘‘‘ # 0202 使用python提供的語法糖‘@‘(優化方法) # 引用時間模塊 import time # 定義裝飾器 def timmer(f): # f = func1 函數的內存地址 def inner(): start_time = time.time() f() end_time = time.time() print(‘此函數的執行時間是%s‘ % (end_time - start_time)) return inner ‘‘‘ @timmer的作用 1.@timmer相當於func1 = timmer(func1) 2.@timmer需要寫在函數定義前,這可以保證函數在被調用時即執行裝飾器的功能,無論多少次調用只要寫一次即可。 3.@timmer可以把定義的函數看做為一行來進行使用,實際上當執行到語法糖的時候,尋找最近的函數,完成1中的等式。 ‘‘‘ @timmer # 切記將語法糖寫在函數定義之前 def func1(): time.sleep(0.6) print(‘來了,老弟‘) func1() # inner() @timmer def func2(): time.sleep(0.6) print(‘來le‘) func2() # 03 被裝飾的函數帶有參數 import time def timmer(f): # f = func1 函數的內存地址 def inner(*args, **kwargs): start_time = time.time() f(*args, **kwargs) # 真正執行函數func1的一句 end_time = time.time() print(‘此函數的執行時間是%s‘ % (end_time - start_time)) return inner @timmer # func1 = timmer(func1) def func1(a): time.sleep(0.6) print(‘來了,%s‘ % (a)) func1(‘alex‘) # 輸出結果: 來了,alex 此函數的執行時間是0.6000347137451172 # 04 被裝飾函數有返回值 import time def timmer(f): # f = func1 函數的內存地址 def inner(*args, **kwargs): start_time = time.time() ret = f(*args, **kwargs) # 真正調用func1函數 end_time = time.time() print(‘此函數的執行時間是%s‘ % (end_time - start_time)) return ret return inner @timmer # func1 = timmer(func1) def func1(a): time.sleep(0.6) print(‘來了,%s‘ % (a)) return 666 print(func1(‘alex‘)) # print(inner(‘alex‘)) # 輸出結果:來了,alex 此函數的執行時間是0.600034236907959 666
3.裝飾器的應用
# 登錄認證的應用(示例,具體完整內容詳見作業4博客園的登錄驗證) login_status = { ‘username‘: None, ‘status‘: False, } def login(f): def inner(*args, **kwargs): if login_status[‘status‘]: ret = f(*args, **kwargs) return ret else: print(‘請先登錄‘) username = input(‘請輸入用戶名‘).strip() password = input(‘請輸入密碼‘).strip() if username == ‘二狗‘ and password == ‘123‘: login_status[‘username‘] = username login_status[‘status‘] = True ret = f(*args, **kwargs) return ret return inner @login def article(): print(‘歡迎訪問文章頁面‘) @login def dariy(): print(‘歡迎訪問日記頁面‘) @login def comment(): print(‘歡迎訪問評論頁面‘) dic = { 1: login, 2: article, 3: dariy, 4: comment, } while 1: print(‘‘‘ 歡迎來到博客園首頁: 1,登錄 2,文章頁面 3,日記頁面 4,評論頁面 ‘‘‘) num = input(‘請輸入數字:‘).strip() dic[int(num)]()
4.裝飾器的進階
‘‘‘ 整體說明: 01 帶參數的裝飾器 (1)應用場景1:對500個函數加上裝飾器,之後去掉,之後再加上。 (2)帶參數的裝飾器相當於增加一個開關,可以讓裝飾器生效與失效。 02 多個裝飾器裝飾一個函數 ‘‘‘ # 01 帶參數的裝飾器的的標準形式: def login(a, b): print(a, b) def wrapper(f): def inner(*args, **kwargs): ret = f(*args, **kwargs) return ret return inner return wrapper @login(1,2) def func1(): print(111) func1() # 02 帶參裝飾器的舉例 login_status = { ‘username‘: None, ‘status‘: False, } def login(a): def wrapper(f): def inner(*args, **kwargs): if a: # 判斷裝飾器是否生效,如果flag = True則執行裝飾器,否則則不執行裝飾器 if login_status[‘status‘]: ret = f(*args, **kwargs) return ret else: print(‘請先登錄‘) username = input(‘請輸入用戶名‘).strip() password = input(‘請輸入密碼‘).strip() if username == ‘二狗‘ and password == ‘123‘: login_status[‘username‘] = username login_status[‘status‘] = True ret = f(*args, **kwargs) return ret else: ret = f(*args, **kwargs) return ret return inner return wrapper flag = False # 設置開關,定義裝飾器生效和失效 @login(flag) def func1(): print(111) @login(flag) def func2(): print(12) @login(flag) def func3(): print(131) func1() login_status = { ‘username‘: None, ‘status‘: False, } def login(a): def wrapper(f): def inner(*args, **kwargs): if login_status[‘status‘]: ret = f(*args, **kwargs) return ret else: print(‘請先登錄‘) ‘‘‘根據a 京東,天貓 去驗證不同密碼‘‘‘ username = input(‘請輸入用戶名‘).strip() password = input(‘請輸入密碼‘).strip() if username == ‘二狗‘ and password == ‘123‘: login_status[‘username‘] = username login_status[‘status‘] = True ret = f(*args, **kwargs) return ret return inner return wrapper @login(‘京東‘) def jd(): print(‘歡迎訪問文章頁面‘) @login(‘京東‘) def jdmarkte(): print(‘歡迎訪問日記頁面‘) @login(‘天貓‘) def TM(): print(‘歡迎訪問評論頁面‘) @login(‘天貓‘) def TMmarke(): print(‘歡迎訪問評論頁面‘) # 02 多個裝飾器裝飾一個函數 def wrapper1(func): # func = 函數名f def inner1(): print(‘wrapper1 ,before func‘) # 2 func() # 函數f print(‘wrapper1 ,after func‘) # 4 return inner1 def wrapper2(func): # func = inner1 def inner2(): print(‘wrapper2 ,before func‘) # 1 func() # inner1() print(‘wrapper2 ,after func‘) # 5 return inner2 @wrapper2 # f = wrapper2(f) 裏面的f 是inner1 外面的f 是inner2 @wrapper1 # f = wrapper1(f) 裏面的f是函數名f 外面的f是 inner1 def f(): print(‘in f‘) # 3 f() # inner2() # 輸出結果: ‘‘‘ wrapper2 ,before func wrapper1 ,before func in f wrapper1 ,after func wrapper2 ,after func ‘‘‘ ‘‘‘ 執行順序說明:(可以簡答理解為先自上而下之後再自下而上) 1.首先,遵循自上而下的原則,依次開辟wrapper1和wrapper2的空間。 2.執行到裝飾器後,依據就近原則,先執行裝飾器wrapper1,即f = wrapper1(f),之後執行裝飾器wrapper2,即f = wrapper1(f) 此時,f = wrapper1(f) 裏面的f是函數名f 外面的f是 inner1,f = wrapper2(f) 裏面的f 是inner1 外面的f 是inner2。 3.執行inner2函數(inner1是函數inner2的變量),首先先打印“wrapper2 ,before func”,之後將變量inner1賦值給f。 4.執行inner1函數(f為函數inner1的變量),首先打印‘wrapper1 ,before func’,之後執行f(),即打印‘in f’,執行完成後打印 ‘wrapper1 ,after func‘,函數inner1執行完成,即wrapper2中的func()函數執行完成。 5.最後執行wrapper2種的打印語句,將‘wrapper2 ,after func’打印輸出。 ‘‘‘
5.叠代器與生成器
‘‘‘ 整體說明: 01 可叠代對象:內部含有‘__iter__’方法的數據就是可叠代對象,包括list str tuple set dict range() 文件句柄 02 叠代器:內部含有‘__iter__’方法的並且含有‘__next__’方法的就是叠代器 03 可叠代對象 ----> 叠代器(轉化) 04 叠代器的作用: (1)非常非常的節省內存 (2)滿足惰性機制 (3)一條路走到黑(可以理解為類似於指針,下次讀取時從上去讀取結束時的位置開始讀) 05 利用while循環模擬for循環機制。 (1)將可叠代對象轉化成叠代器 (2)利用next 進行取值 (3) 利用異常處理終止循環。 06 生成器:自己用python代碼寫的叠代器 本質就是叠代器 (1)函數式寫法: a)只要函數中出現yield,那麽 他就不是函數了,他是生成器函數。 b)yield和return的區別 i)return 結束函數 給函數返回值 ii)yield 不會結束生成器函數,next 對應一個yield進行取值 (2)生成器表達式 ‘‘‘ # 01 可叠代對象 # 判斷方法 s1 = ‘二狗的周末生活‘ print(dir(s1)) # 用dir可以打印所有的方法 print(‘__iter__‘ in dir(s1)) # 判斷是否包含_iter_方法,如果包含結果是True,如果不包含結果為False # 02 叠代器 # 判斷方法 f1 = open(‘regsiter‘, encoding=‘utf-8‘) print(‘__iter__‘ in dir(f1)) # 判斷是否包含_iter_方法,如果包含結果是True,如果不包含結果為False print(‘__next__‘ in dir(f1)) # 判斷是否包含_next_方法,如果包含結果是True,如果不包含結果為False f1.close() # 03 可叠代對象->叠代器 l1 = [1, 2, 3, ‘alex‘] iter1 = iter(l1) # l1.__iter__(),將可叠代對象轉化為叠代器 print(iter1) # 打印出的一個元素的地址<list_iterator object at 0x00000000021DE278> print(iter1.__next__()) print(iter1.__next__()) print(iter1.__next__()) print(iter1.__next__()) # for循環的方式依次輸出 for i in iter1: print(i) # 04 利用while循環模擬for循環 的機制。 l1 = [1, 2, 3, ‘alex‘] iter1 = l1.__iter__() while 1: try: print(iter1.__next__()) except StopIteration: # except是用來異常處理的作用 break # 05 生成器 # 0501 函數式寫法 構建生成器 def func1(): # print(111) # print(222) yield 3 yield 4 yield 5 yield 6 yield 7 g = func1() # 生成器對象 print(g) # 打印出生成器的地址 print(g.__next__()) # print(next(g)),一個next 對應一個 yield print(g.__next__()) print(g.__next__()) print(g.__next__()) # 0502 生成器舉例 def cloth(): for i in range(1,201): print(‘老男孩老年體恤%s號‘ % (i)) cloth() def cloth1(): for i in range(1,201): yield ‘老男孩老年體恤%s號‘ % (i) g = cloth1() for i in range(5): print(g.__next__()) for i in range(195): print(g.__next__())
6.列表推導式與生成器表達式
‘‘‘ 整體說明: 01 列表推導式 (1)凡是用列表推導式能構建的數據,python代碼都可以構建,列表推導式不能構建的數據,python代碼亦可以可以構建。 (2)兩種模式: a)循環模式: [變量(加工後的變量) for 變量 in iterable] b)篩選模式:[變量(加工後的變量) for 變量 in iterable if 條件] 02 生成器表達式: (1)兩種模式: a)循環模式: (變量(加工後的變量) for 變量 in iterable) b)篩選模式:(變量(加工後的變量) for 變量 in iterable if 條件) (2)生成器表達式與列表推導式用() 括起來,其他規則與列表推導式一致。 03 列表推導式,生成器表達式的優缺點。 (1)優點:構造簡單,一行完成 (2)缺點: a)不能排錯 b)不能構建復雜的數據結構 ‘‘‘ # 01 循環模式: [變量(加工後的變量) for 變量 in iterable] # 舉例:用列表推導式:構建一個列表:[‘python1期‘, ‘python2期‘....,‘python24期‘] print([‘python%s期‘ % i for i in range(1, 25)]) # 02 篩選模式 [變量(加工後的變量) for 變量 in iterable if 條件] # 舉例: # 10以內所有數的平方。 print([i * i for i in range(1, 11)]) # 30以內能被3整除的數的平方。 print([i ** 2 for i in range(1, 31) if i % 3 == 0]) # l1 = [‘alex‘, ‘taibai‘, ‘wusir‘, ‘re‘, ‘ab‘],過濾掉長度小於3的字符串列表,並將剩下的轉換成大寫字母。 print([i.upper() for i in l1 if len(i) > 3])
python基礎(四)