1. 程式人生 > >8 函式、迭代器、閉包

8 函式、迭代器、閉包

一 函式

  • 作用:是對程式碼塊進行封裝和定義
  • 形式:def func():

       函式體

  • 函式引數的位置關係:位置引數 >  *args > 預設值引數 > **kwargs  
  • 函式引數的傳遞:func(*[1,2,3],**{1:2,3:5})類似解包的方式打散傳遞。
  • 函式的名稱空間:

    1. 全域性名稱空間--> 我們直接在py⽂檔案中, 函式外宣告的變數量都屬於全域性名稱空間       

    2. 區域性名稱空間--> 在函式中宣告的變數量會放在區域性名稱空間       

    3. 內建名稱空間--> 存放python直譯器為我們提供的名字, list, tuple, str, int這些都是內建名稱空間

    載入順序:內建——>全域性——>區域性

    取值順序:區域性——>全域性——>區域性

    nonlocal 宣告內部函式中區域性變數 global 宣告內部函式變數為全域性變數 這兩個一般都不用。

二 閉包

 A.函式名相關知識

  1.  函式名是一個特殊的變數,存放的是函式的地址,加一個括號就可以執行函數了。
  2.  函式名可以賦值給其他變數
  3. 函式名可以當做容器類的元素

  4.  函式名可以當做函式的引數   

    
def func():
    print("吃了了麼")
def func2(fn):
    print("我是func2")
    fn()    # 執⾏行行傳遞過來的fn
    print("我是func2")
func2(func)  #  把函式func當成引數傳遞給func2的引數fn
函式名當引數

  5.函式名可以作為函式的返回值

   
def func():
    print("吃了了麼
") def func2(): print("我是func2") return func fn = func2() #fn指向func()函式的地址 fn()
作為函式返回值

 B.閉包

  定義:記憶體函式對外層函式(非全域性變數)變數的引用。

    
def func():
    a = 10
    print("吃了了麼")
    def func2():
        print(a)
        print("我是func2")
    return func2
fn = func()
fn()
print(fn.__closure__)#(<cell at 0x019FD530: int object at 0x5E9FE3A0>,)
使用__closure__驗證函式是否為閉包函式

  閉包的作用:由它我們可以引出閉包的好處.  由於我們在外界可以訪問內部函式. 那這個時候內部函 數訪問的時間和時機就不一定了, 因為在外部, 我可以選擇在任意的時間去訪問內部函式. 這個時候想想我們之前說過, 如果一個函式執行完畢. 則這個函式中的變量以及區域性命名 空間中的內容都將會被銷燬.  在閉包中如果變量被銷燬了. 那內部函式將不能正常執⾏所以python規定. 如果你在內部函式中訪問了外層函式中的變量. 那麼這個變量將不會消亡. 將會常駐在記憶體中. 也就是說. 使⽤用閉包, 可以保證外層函式中的變量在記憶體中常駐. 這樣做 有什麼好處呢? 非常⼤大的好處. 一個關於爬⾍蟲的程式碼: 

    
from urllib.request import urlopen
def but():
    content = urlopen("http://www.xiaohua100.cn/index.html").read()
    def get_content():        
        return content
    return get_content
fn = but()  # 這個時候就開始載入校花100的內容  
content = fn()  # 獲取內容 
print(content) 
content2 = fn() # 後⾯面需要⽤用到這⾥裡里⾯面的內容就不不需要在執⾏行行⾮非常耗時的⽹網路連線操作了了
print(content2)# 重新獲取內容 
簡單爬蟲

 C 迭代器

  回顧:之前學過的可迭代物件,set、tuple、list、str、dict等

  通過dir方法檢視函式類中的方法可以確定是否為可迭代的,如果含有__iter__方法的就說明是個可迭代的物件。

  
print(dir(range))#'__iter__'
print(dir(list))
View Code

  還有一種方法檢視:

  
l = [1,2,3]
l_iter = l.__iter__() 
from collections import Iterable #匯入可迭代模組
from collections import Iterator#匯入迭代器模組
print(isinstance(l,Iterable))    #True
print(isinstance(l,Iterator))    #False
print(isinstance(l_iter,Iterator))    #True
print(isinstance(l_iter,Iterable))    #True
View Code

  for 的迴圈機制       

  
lis = '我愛你祖國'
c = lis.__iter__() #拿到一個迭代器
print(c.__next__())#
print(c.__next__())#
print(c.__next__())#
print(c.__next__())#
print(c.__next__())#
print(c.__next__()) #StopIteration
迴圈    
# for i in '我愛你祖國':
#     print(i)
lis = '我愛你祖國'
c = lis.__iter__() #首先拿到一個迭代器
while 1:
    try:
        m = c.__next__()
        print(m)
    except StopIteration:
        break
for迴圈的機制

D 總結

  1. Iterable: 可迭代物件. 內部包含__iter__()。
  2. 函式Iterator: 迭代器. 內部包含__iter__() 同時包含__next__().         
  3. 迭代器的特點: 1. 節省記憶體.  2. 惰性機制   3. 不能反覆, 只能向下執行.   

    我們可以把要迭代的內容當成子彈. 然後呢. 獲取到迭代器__iter__(), 就把子彈都裝在彈夾中.  然後發射就是__next__()把每⼀個子彈(元素)打出來. 也就是說, for迴圈的時候. 一開始的 時候是__iter__()來獲取迭代器. 後面每次獲取元素都是通過__next__()來完成的. 當程式遇到 StopIteration將結束迴圈.