迭代器協議:某對象必須提供一個__next__()方法,執行方法要麼返回迭代中的下一項,要麼引發一個Stopiteration異常,以終止迭代(只能日後走,不能往前退)python
協議是一種規範,可迭代對象實現了迭代器協議,python的內部工具(如for循環、sum、min、max函數),使用迭代器協議訪問對象數據庫
可迭代對象(Iterator):實現了迭代器協議的對象(如何實現:對象內部定義了一個__iter__()方法),也就是可迭代對象內部要包含__iter__() 函數session
迭代器(Iterator):內部包含了__iter()__() ,同時也包含__next__()閉包
先經過__iter__()方法將可迭代對象轉換爲迭代器,再調用迭代器中的__next__()方法遍歷,最後再抓取結束時的異常app
print("解析for循環的工做機制:") num = [1, 2, 3, 4, 5] for i in num: # 工做機制: num.__iter__() ------> num.__next__() print(i)
1)可迭代對象與迭代器之間的關係函數
2)迭代器的特色工具
3)isinstance()判斷對象是否爲Iterable對象:網站
from collections import Iterable print(isinstance([], Iterable))
print("使用while循環遍歷一個列表:") index = 0 while index < len(num): print(num[index]) index += 1 print("利用迭代器協議遍歷一個列表:") iter = num.__iter__() print(iter.__next__()) print(iter.__next__()) print(iter.__next__()) print("解析文件操做中對於文件內容的遍歷:") f = open("test.txt", "r") f_iter = f.__iter__() # 這裏先將整個文件轉換爲一個迭代器,以後對迭代器調用__next__()方法,只在有須要的時候才加載文件一行內容 # 當取出一行內容時,由於沒有賦值給任何變量,因此佔用的內存會被python的自動回收機制回收,因此這種遍歷文件的方式只會動態的佔用一小塊內存 print(f_iter.__next__(), end="") print(f_iter.__next__(), end="") print(f_iter.__next__(), end="") print(f_iter.__next__(), end="") print(f_iter.__next__(), end="") f.close() print("next()方法:") # next()方法--->調用__next__()方法 the_num = [1, 2, 3] the_iter = the_num.__iter__() # 也能夠直接使用iter(the_num)方法 print(next(the_iter)) # next(the_iter) -----> 調用 the_iter.__next__()
生成器(generator)就是可迭代對象(它在內部實現了迭代器協議)spa
生成器在python中的兩種表達形式:code
觸發生成器的方式:
1)生成器函數
def func(): print("如今開始執行生成器函數:") print("First----->") yield "第一步" print("Second----->") yield "第二步" print("Third") yield "第三步" print("End") yield "生成器函數調用完畢" f = func() print(f.__next__()) # __next__()函數調用接受到的返回值就是yield後面的值 print(f.__next__()) print(f.__next__()) print(f.__next__())
2)用yield方式的生成器實現字典中文件的內容查找
def get_num(): f = open("population.txt", "r", encoding="utf-8") # 這個文件中的每一行都是一個字典 for i in f: yield i # 這裏返回的 i 爲字符串類型 population = eval(get_num().__next__()) # 這裏經過eval()函數從新恢復了文件中數據的數據類型,恢復成了字典 print("%s的人口數爲%s" % (population["city"], population["population"])) # 注意:生成器只能遍歷一次 # 用生成器表達式的方式實現字典中文件數字的求和 f = open("population.txt", "r", encoding="utf-8") p = sum(eval(i)["population"] for i in f) print(p)
3)send()方法的使用
def my_func(): print("First") send1 = yield 1 # yield後面的值是next方法調用的返回值,而前面的值是yield接收值以後賦值的變量 print("Second") print("這次send傳送的值爲:", send1) send2 = yield 2 print("Third") print("這次send傳送的值爲:", send2) yield 3 print("End") m = my_func() # 這裏並不會執行這個函數,由於只要函數內部定義了yield關鍵字,函數就變成了生成器,只有經過next方法調用 print(m.__next__()) print(m.send(None) ) # 這裏的send(None),就至關於__next__()方法,觸發一次生成器 # send()函數將值傳遞給當前停留位置的yield,以後這個yield會將值傳遞給前面的變量 print(m.send("這是第二次send"))
4)yield from
def func(): lst1 = ['衛龍','老冰棍','北冰洋','牛羊配'] lst2 = ['饅頭','花捲','豆包','大餅'] yield from lst1 yield from lst2 g = func() for i in g: print(i) # 衛龍 # 老冰棍 # 北冰洋 # 牛羊配 # 饅頭 # 花捲 # 豆包 # 大餅
5)額外
def func3(): for i in range(10): yield i t = func3() # for i in t: # 由於for循環的工做機制就是使用迭代器協議調用next方法,因此會觸發生成器函數 # print(i) li1 = (i for i in t) # 這裏li1會獲得一個生成器的地址 li2 = (i for i in li1) print(type(li1)) print(list(li1)) # 這裏的list函數中會用for循環機制取值,從而觸發生成器,如今這個位置li1中的值已經被取完了 print(list(li2)) # 因li1中的值已經被取完了,因此li2如今已經取不到值了
1)列表推導式
name = "hgzero" ret = "me" if name == "hgzero" else "other" # 若name等於hgzero,則返回me,不然返回other print(ret)
list1 = [i for i in range(10)] # 列表解析會將生成的列表直接放於內存中,會佔用較大的內存 print(list1) list2 = ["數字%d" % i for i in range(10)] # for循環處理後將i依次往前面傳遞 print(list2)
print("三元表達式和列表解析結合") list3 = ["數字%d" % i for i in range(10) if i > 5] # 這裏不能使用else,由於已經構成了三元表達式了 print(list3)
2)生成器推導式
print("生成器表達式:") list2 = ("數字%d" % i for i in range(10)) # 將列表解析表達式外圍的中括號換成小括號就變成了一個生成器 # 生成器表達式更節省內存 print(list2) print(list2.__next__()) print(list2.__next__()) print(list2.__next__()) print(list2.__next__()) # 能夠將生成器表達式傳遞給sum()等函數,以節省佔用內存的大小 print(sum(i for i in range(100000))) # 這裏的sum函數裏面的生成器表達式不須要加括號 # 若是直接在sum中傳入一個很是大的列表,會形成佔用太多內存而致使機器卡死,而用生成器的方式傳入則會動態的佔用很小的一片內存
3)字典推導式
lst1 = ['jay','jj','huazai'] lst2 = ['周杰倫','林俊杰','劉德華'] dic = {lst1[i]:lst2[i] for i in range(len(lst1))} print(dic)
4)集合推導式
lst = [1,2,3,-1,-3,-7,9] s = {abs(i) for i in lst} print(s)
import time # def producer(): # ret = [] # for i in range(100): # time.sleep(0.1) # ret.append("包子%s" % i) # return ret # # def consumer(ret): # for index, baozi in enumerate(ret): # time.sleep(0.1) # print("第%d我的來了,吃了第%s個包子" % (index, baozi)) # # p = producer() # consumer(p) def producer(): c1 = consumer("hgzero") c2 = consumer("wuzhihao") c1.__next__() c2.__next__() for i in range(10): time.sleep(1) print("如今包子 %s 已經作好了!" % i) c1.send("第%s個包子" % i) c2.send("第%s個包子" % i) def consumer(name): print("吃包子開始!") while True: baozi = yield time.sleep(1) print("我是 %s , 如今開始吃 %s 包子" % (name, baozi)) producer()
在一個外函數中定義了一個內函數,內函數裏運用了外函數的臨時變量,而且外函數的返回值是內函數的引用,這樣就構成了一個閉包。簡單來講,閉包就是內層函數,對外層函數變量的引用。
通常狀況下,若是一個函數執行結束,則這個函數的內部的變量以及局部命名空間中的內容都會被釋放掉。可是在閉包中,若是外函數在結束的時候發現有本身的臨時變量未來會在內部函數中用到,就把這個臨時變量綁定給了內部函數,而後本身再結束。也就說,使用閉包,能夠保證外部函數中的變量在內存中常駐,以供後面的程序使用。
其實閉包中外部函數的返回值定義成內部函數的地址,是爲了防止內部函數被垃圾回收機制回收。
def func1(): def func2(): s = '地主家的傻兒子' def func3(): print(s) return func3 return func2 func1()()()
# 解壓序列: a, *b, c = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 這裏的 * 號表示全部的意思 print(a) print(b) print(c) # 交換兩個變量的值: a = 1 b = 2 print("經過中間變量的形式交換:") c = a a = b b = c print(a, b) print("另外兩種不引入額外變量實現交換的方式:") f1 = 1 f2 = 2 f1, f2 = f2, f1 print(f1, f2) n1 = 1 n2 = 2 n1 = n1 + n2 n2 = n1 - n2 n1 = n1 - n2 print(n1, n2)
1)用高階函數的方式實現裝飾器的功能:不合格,由於這種方式會使工做函數調用了兩次
# 1.不修改被修飾函數的源代碼 # 2. 不修改被修飾函數的調用方式 # 裝飾器 = 高階函數+函數嵌套+閉包 import time # 用高階函數的形式想實現裝飾器的功能,不合格,由於這種方式會使工做函數調用了兩次 def work_func(): time.sleep(1) print("這裏是work_func函數") def dec_func(func): start_time = time.time() func() finish_time = time.time() print("這個函數運行的時間是%d" % (finish_time-start_time)) return func work_func = dec_func(work_func) # 這裏在賦值以前就已經執行了dec_func(work_func)函數 work_func() # 這裏又執行了一便work_func函數
2)用高階函數 + 函數嵌套 + 閉包的方式實現裝飾器
import time def work_func2(): time.sleep(1) print("這裏是work_func2函數") def dec_func2(func): def wapper(): start_time = time.time() func() finish_time = time.time() print("這個函數運行的時間是%d" % (finish_time - start_time)) return wapper work_func2 = dec_func2(work_func2) # 這裏執行dec_func2函數時遭遇一個閉包,獲得的是閉包wrapper函數的內存地址(並無執行它) work_func2() # 這裏執行上面獲得的閉包函數,即執行wapper()函數
3)用「語法糖」的形式實現裝飾器
import time def dec_func3(func): def wapper(): start_time = time.time() func() finish_time = time.time() print("這個函數運行的時間是%d" % (finish_time - start_time)) return wapper @dec_func3 # 用「語法糖」的形式實現裝飾器 ,至關於 work_func3 = dec_func3(work_func3) def work_func3(): time.sleep(1) print("這裏是work_func3函數") work_func3() def dec_func4(func): # 裝飾器改進,添加返回值和多參數功能 def wapper(*args, **kwargs): start_time = time.time() res = func(*args, **kwargs) # func()函數的返回值就是work_func函數中的返回值,用res接收以後,再返回出去 finish_time = time.time() print("這個函數運行的時間是%d" % (finish_time - start_time)) return res return wapper @dec_func4 # work_func4 = dec_func3(work_func3) 這時執行work_func4函數就是執行wapper函數,由於dec_func3函數返回的就是wapper的地址 def work_func4(name, age): time.sleep(1) print("這裏是work_func4函數") print("Name:【%s】,Age:【%d】" % (name, age)) return 12345 # 這時,work_func函數的返回值就是dec_func函數的閉包---> wapper函數的返回值 work_func4("hgzero", 21)
import time user = [ {"username": "hgzero", "passwd": "123"}, {"username": "wzh", "passwd": "123"}, {"username": "hg", "passwd": "123"}, {"username": "zero", "passwd": "123"}, {"username": "abc", "passwd": "123"} ] login_dict = {"username": None, "login": False} # 這裏用這個字典模擬session的功能 def login_func(func): def wrapper(*args, **kwargs): if login_dict["username"] and login_dict["login"]: ret = func(*args, **kwargs) return ret while True: username = input("請輸入用戶名:").strip() passwd = input("請輸入密碼:").strip() for dict in user: if dict["username"] == username and dict["passwd"] == passwd: login_dict["username"] = username login_dict["login"] = True ret = func(*args, **kwargs) return ret else: print("用戶名或密碼錯誤!") time.sleep(1) print("請從新輸入----->") return wrapper @login_func def index(): print("歡迎來到zero的網站主頁!") @login_func def home(name): print("【%s】,歡迎來到我的中心!" % (name)) @login_func def shopping(name): print("【%s】,如今您的購物車中有 %s , %s , %s " % (name, "牛奶", "香蕉", "芒果")) index() home("python工程師") shopping("python工程師")
import time user = [ {"username": "hgzero", "passwd": "123"}, {"username": "wzh", "passwd": "123"}, {"username": "hg", "passwd": "123"}, {"username": "zero", "passwd": "123"}, {"username": "abc", "passwd": "123"} ] login_dict = {"username": None, "login": False} # 這裏用這個字典模擬session的功能 def func(db_type): def login_func(func): print("這個數據庫的類型是:", db_type) def wrapper(*args, **kwargs): if login_dict["username"] and login_dict["login"]: ret = func(*args, **kwargs) return ret while True: username = input("請輸入用戶名:").strip() passwd = input("請輸入密碼:").strip() for dict in user: if dict["username"] == username and dict["passwd"] == passwd: login_dict["username"] = username login_dict["login"] = True ret = func(*args, **kwargs) return ret else: print("用戶名或密碼錯誤!") time.sleep(1) print("請從新輸入----->") return wrapper return login_func @func("MySQL") # 這裏先執行func("MySQL") ---> index = login_func(index) # 這裏由於後面加了括號,因此是執行了func函數,執行了func函數所獲得的返回值就是login_func函數的地址 # func()函數執行獲得的地址就是login_func,因此這裏就等價因而 @login_func,同時也將參數傳進去了,巧妙的運用了閉包的原理 def index(): print("歡迎來到zero的網站主頁!") @func("Mongodb") def home(name): print("【%s】,歡迎來到我的中心!" % (name)) @func("Redis") def shopping(name): print("【%s】,如今您的購物車中有 %s , %s , %s " % (name, "牛奶", "香蕉", "芒果")) index() home("python工程師") shopping("python工程師")