python函數名的運用,閉包,叠代器
一.函數名的運用
函數名是一個變量,但它是一個特殊的變量,與括號配合可以執行函數的變量.
1.函數名的內存地址
1 def func(): 2 print("呵呵") 3 print(func) 4 結果: 5 function func at 0x1101e4e
2.函數名可以賦值給其他變量
1 def func(): 2 print("呵呵") 3 print(func) 4 a = func # 把函數當成一個變量賦值給另一個變量 5 a() # 函數調用 func()
3.函數名可以當做容器類的元素
1 def func1(): 2 print("呵呵") 3 def func2(): 4 print("呵呵") 5 def func3(): 6 print("呵呵") 7 def func4(): 8 print("呵呵") 9 lst = [func1, func2, func3] 10 for i in lst: 11 i()
4.函數名可以當做函數的參數
1 def func(): 2 print("吃了麽") 3 def func2(fn): 4 print("我是func2") 5 fn() # 執行傳遞過來的fn 6 print("我是func2") 7 func2(func) #把函數func當成參數傳遞給func2的參數.
5.函數名可以作為函數的返回值
1 def func_1(): 2 print("這裏是函數1") 3 def func_2(): 4 print("這裏是函數2") 5 print("這裏是函數1") 6 return func_2 7 fn = func_1() # 執行函數1. 函數1返回的是函數2, 這時fn指向的就是上面函數2 8 fn() # 執行上面返回的函數
二.閉包
什麽是閉包?閉包就是內層函數,對外層函數(非全局)的變量的引用.叫閉包
1 def func1(): 2 name = "alex" 3 def func2(): 4 print(name) # 閉包 5 func2() 6 func1() 7 結果: 8 alex
我們可以使用__closure__來檢測函數是否是閉包.使用函數名.__closure__返回cell就是閉包.返回None就不是閉包.
1 def func1(): 2 name = "alex" 3 def func2(): 4 print(name) # 閉包 5 func2() 6 print(func2.__closure__) # (<cell at 0x10c2e20a8: str object at 7 #0x10c3fc650>,) 8 func1()
問題,如何在函數外邊調用內部函數呢?
1 def outer(): 2 name = "alex" 3 # 內部函數 4 def inner(): 5 print(name) 6 return inner 7 8 fn = outer() # 訪問外部函數, 獲取到內部函數的函數地址 9 fn() # 訪問內部函數
那如果多層嵌套呢?很簡單,只需要一層一層的往外層返回就行了
1 def func1(): 2 def func2(): 3 def func3(): 4 print("嘿嘿") 5 return func3 6 return func2 7 8 func1()()()
由它我們可以引出閉包的好處.由於我們在外界可以訪問內部函數,那這個時候內部函數訪問的時間和時機就不一定了,因為在外部,我可以選擇在任意時間去訪問內部函數.這個時候,想一想,我們之前說過,如果一個函數執行完畢.則這個函數中的變量以及局部命名空間中的內容都會被銷毀.在閉包中,如果變量被銷毀了,那內部函數將不能正常執行.所以,python規定.如果你在內部函數中訪問了外層函數中的變量.那麽這個變量將不會消亡.將會常駐在內存中,也就是說.使用閉包,可以保證外層函數中的變量在內存中常駐.這樣做有什麽好處呢?非常大的好處.我們來看一個爬蟲代碼:
1 from urllib.request import urlopen 2 def but(): 3 content =urlopen("http://www.xiaohua100.cn/index.html").read() 4 def get_content(): 5 return content 6 return get_conte 7 fn = but() # 這個時候就開始加載校花100的內容 8 # 後面需要用到這裏面的內容就不需要在執行非常耗時的網絡連接操作了 9 content = fn() # 獲取內容 10 print(content) 11 content2 = fn() # 重新獲取內容 12 print(content2)
綜上,閉包的作用就是讓變量能夠常駐內存.供後面的程序使用
三.叠代器
什麽叫做叠代器?叠代器英文意思是iterator。
1 l = [1,2,3,4] 2 l_iter = l.__iter__() # 將可叠代的轉化成叠代器 3 item = l_iter.__next__() 4 print(item) 5 item = l_iter.__next__() 6 print(item) 7 item = l_iter.__next__() 8 print(item) 9 item = l_iter.__next__() 10 print(item) 11 item = l_iter.__next__() 12 print(item)
叠代器遵循叠代器協議:必須擁有__iter__方法和__next__方法。
for循環,能遍歷一個可叠代對象,他的內部到底進行了什麽?
- 將可叠代對象轉化成叠代器。(可叠代對象.__iter__())
- 內部使用__next__方法,一個一個取值。
- 加了異常處理功能,取值到底後自動停止。
用while循環模擬for循環:
1 l = [1,2,3,4] 2 l_iter = l.__iter__() 3 while True: 4 try: 5 item = l_iter.__next__() 6 print(item) 7 except StopIteration: 8 break
為什麽要有for循環?
基於上面講的列表這一大堆遍歷方式,聰明的你立馬看除了端倪,於是你不知死活大聲喊道,你這不逗我玩呢麽,有了下標的訪問方式,我可以這樣遍歷一個列表啊
1 =[1,2,3] 2 3 index=0 4 while index < len(l): 5 print(l[index]) 6 index+=1 7 8 #要毛線for循環,要毛線可叠代,要毛線叠代器
沒錯,序列類型字符串,列表,元組都有下標,你用上述的方式訪問,perfect!但是你可曾想過非序列類型像字典,集合,文件對象的感受,所以嘛,年輕人,for循環就是基於叠代器協議提供了一個統一的可以遍歷所有對象的方法,即在遍歷之前,先調用對象的__iter__方法將其轉換成一個叠代器,然後使用叠代器協議去實現循環訪問,這樣所有的對象就都可以通過for循環來遍歷了,而且你看到的效果也確實如此,這就是無所不能的for循環,最重要的一點,轉化成叠代器,在循環時,同一時刻在內存中只出現一條數據,極大限度的節省了內存~
四.總結
Iterable:可叠代對象.內部包含__iter__()函數
Iterator:叠代器.內部包含__iter__()同時包含__next__().
叠代器的特點:
1.節省內存.
2.惰性機制
3.不能反復,只能向下執行.
我們可以把要叠代的內容當成子彈.然後呢,獲取到叠代器__iter__(),就把子彈都裝在彈夾中.然後發射就是__next__()把每一個子彈(元素)打出來.也就是說,for循環的時候,一開始的時候是__iter__()來獲取叠代器.後面每次獲取的元素都是通過__next__()來完成的.當程序遇到StopIteration將結束循環.
python函數名的運用,閉包,叠代器