Python基礎九函數進階(二)
回顧一下
函數名的本質就是函數的內存地址
1可以被引用
2可以當做容器類性的元素
3可以當做函數的參數和返回值
一、閉包
閉包的含義:內部函數引用外部作用域(非全局)的變量 (內部函數指的是函數內部定義的函數)
有與有了作用域的關系,我們就不能拿到函數內部的變量和函數了。如果我們有需求就是想拿到那怎麽做呢?返回呀!
我們都知道函數內的變量我們想要在函數外不用,可以直接返回這個變量,那麽如果我們想在函數外部調用函數內部的函數呢?
是不是直接就把這個函數名字返回就好了呢?
這才是閉包函數最常用的方法
def func(): name = ‘eva‘ def inner():print(name) return inner f = func() f()
判斷閉包的方法__closure__
#輸出的__closure__有cell元素 :是閉包函數 def func(): name = ‘eva‘ def inner(): print(name) print(inner.__closure__) return inner f = func() f()
#輸出的__closure__為None :不是閉包函數 name = ‘egon‘ def func2(): def inner():print(name) print(inner.__closure__) return inner f2 = func2() f2()
閉包嵌套
def wrapper(): money = 1000 def func(): name = ‘eva‘ def inner(): print(name,money) return inner return func f = wrapper() i = f() i()
爬蟲裏的閉包
from urllib.request importurlopen def index(): url = "https://www.cnblogs.com/gzying-01/" def get(): return urlopen(url).read() return get xiaohua = index() content = xiaohua() print(content.decode(‘utf-8‘)) # 解碼中文顯示
二、叠代器
1、首先什麽是可叠代對象?
字符串、列表、元組、字典、集合都可以被for循環,說明他們都是可叠代的。
那我們如何來證明呢?上代碼:
from collections import Iterable l = [1,2,3,4] t = (1,2,3,4) d = {1:2,3:4} s = {1,2,3,4} print(isinstance(l,Iterable)) # 返回bool值 print(isinstance(t,Iterable)) print(isinstance(d,Iterable)) print(isinstance(s,Iterable))
#返回結果
True
True
True
True
2、可叠代協議
我們現在是從結果分析原因,能被for循環的就是“可叠代的”,但是for怎麽知道誰是可叠代的?
假如我們自己寫了一個數據類型,希望這個數據類型裏的東西可以被使用for循環一個個取出來,那我們就必須滿足for的要求。這個要求就叫做“協議”。
可以被叠代要滿足的要求就叫做可叠代協議。可叠代協議的定義非常簡單,就是內部實現了__inter__方法
print(dir([1,2])) print(dir((2,3))) print(dir({1:2})) print(dir({1,2})) 結果: [‘__add__‘, ‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__delitem__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__gt__‘, ‘__hash__‘, ‘__iadd__‘, ‘__imul__‘, ‘__init__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__mul__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__reversed__‘, ‘__rmul__‘, ‘__setattr__‘, ‘__setitem__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘append‘, ‘clear‘, ‘copy‘, ‘count‘, ‘extend‘, ‘index‘, ‘insert‘, ‘pop‘, ‘remove‘, ‘reverse‘, ‘sort‘] [‘__add__‘, ‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__getnewargs__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__mul__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__rmul__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘count‘, ‘index‘] [‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__delitem__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__getitem__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__iter__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__setitem__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘clear‘, ‘copy‘, ‘fromkeys‘, ‘get‘, ‘items‘, ‘keys‘, ‘pop‘, ‘popitem‘, ‘setdefault‘, ‘update‘, ‘values‘] [‘__and__‘, ‘__class__‘, ‘__contains__‘, ‘__delattr__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__gt__‘, ‘__hash__‘, ‘__iand__‘, ‘__init__‘, ‘__ior__‘, ‘__isub__‘, ‘__iter__‘, ‘__ixor__‘, ‘__le__‘, ‘__len__‘, ‘__lt__‘, ‘__ne__‘, ‘__new__‘, ‘__or__‘, ‘__rand__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__ror__‘, ‘__rsub__‘, ‘__rxor__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__sub__‘, ‘__subclasshook__‘, ‘__xor__‘, ‘add‘, ‘clear‘, ‘copy‘, ‘difference‘, ‘difference_update‘, ‘discard‘, ‘intersection‘, ‘intersection_update‘, ‘isdisjoint‘, ‘issubset‘, ‘issuperset‘, ‘pop‘, ‘remove‘, ‘symmetric_difference‘, ‘symmetric_difference_update‘, ‘union‘, ‘update‘] 驗證結果
總結一下現在我們所知道的:可以被for循環的都是可叠代的,要想可叠代,內部必須有一個__iter__方法。
接著分析,__iter__方法做了啥事兒?
可叠代的:內部必須含有一個__iter__方法。
3、叠代器
什麽叫做叠代器?叠代器英文叫做iterator。
l = [1,2,3,4] l_iter = l.__iter__() # 將可叠代的轉化成叠代器 item = l_iter.__next__() print(item) item = l_iter.__next__() print(item) item = l_iter.__next__() print(item) item = l_iter.__next__() print(item) item = l_iter.__next__() print(item)
叠代器遵循叠代器協議:必須擁有__iter__方法和__next__方法。
for循環,能遍歷一個可叠代對象,他的內部到底進行了什麽?
將可叠代對象轉化成叠代器。(可叠代對象.__iter__())
內部使用了__next__方法,一個一個取值。
交了 異常處理功能,取值到底自動停止。
用為了循環模擬for循環:
l = [1,2,3,4] l_iter = l.__iter__() while True: try: item = l_iter.__next__() print(item) except StopIteration: break
4、為什麽要有for循環?
給予上面的一大堆遍歷方法,貌似看上去就可以滿足我們的遍歷需求了,為何還要搞一個叫做for的玩意兒?
=[1,2,3] index=0 while index < len(l): print(l[index]) index+=1 #要毛線for循環,要毛線可叠代,要毛線叠代器
沒錯,序列類型字符串,列表,元組都有下標,用上述方法遍歷,確實看上去很完美。但是如果遇到非序列類型的比如字典,集合,文件句柄這些家夥,是不是就不靈了。所以,for循環就是基於叠代器協議提供了一個統一的可以遍歷所有對象的方法,即在遍歷之前,先調用對象的__iter__方法將其轉換成一個叠代器,然後使用叠代器協議去實現循環訪問,這樣所有的對象就都可以通過for循環來遍歷了,而且你看到的效果也確實如此,這就是無所不能的for循環,最重要的一點,轉化成叠代器,在循環時,同一時刻在內存中只出現一條數據,極大限度的節省了內存~
Python基礎九函數進階(二)