1. 程式人生 > >python 小兵(6)迭代器

python 小兵(6)迭代器

閱讀目錄

回到頂部

函式名的使用以及第一類物件

函式名的運用

函式名是一個變量, 但它是一個特殊的變量, 與括號配合可以執行函式的變量

1.函式名的記憶體地址

1 2 3 4 def
  func():         print ( "呵呵" ) print (func) 結果: <function func at  0x1101e4ea0 >

2. 函式名可以賦值給其他變數

1 2 3 4 5 def  func():        
print ( "呵呵" )      print (func) =  func     # 把函式當成一個變量賦值給另一個變量 a()      # 函式呼叫 func()

3. 函式名可以當做容器類的元素

1 2 3 4 5 6 7 8 9 10 11 def  func1():         print ( "呵呵" ) def  func2():         print ( "呵呵" ) def  func3():         print ( "呵呵" ) def  func4():         print ( "呵呵" ) lst  =  [func1, func2, func3] for  in  lst:         i()

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

1 2 3 4 5 6 7 def  func():         print ( "吃了麼" ) def  func2(fn):         print ( "我是func2" )         fn()     # 執行傳遞過來的fn         print ( "我是func2" ) func2(func)      # 把函式func當成引數傳遞給func2的引數fn.

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

1 2 3 4 5 6 7 8 9 def  func_1():         print ( "這⾥裡里是函式1" )         def  func_2():                 print ( "這⾥裡里是函式2" )         print ( "這⾥裡里是函式1" )         return  func_2 fn  =  func_1()   # 執行函式1.  函式1返回的是函式2, 這時fn指向的就是上⾯面函式2 fn()     # 執行上面返回的函
回到頂部

閉包

什麼是閉包?  閉包就是內層函式, 對外層函式(非全域性)的變量的引用. 叫閉包

1 2 3 4 5 6 7 8 def  func1():      name  =  "alex"      def  func2():          print (name)          # 閉包      func2() func1() # 結果: alex

我們可以使用__closure__來檢測函式是否是閉包. 使用函式名.__closure__返回cell就是
閉包. 返回None就不是閉包

1 2 3 4 5 6 7 8 9 10 11 12 13 def  func1():      name  =  "alex"      def  func2():          print (name)          # 閉包      func2()      print (func2.__closure__) func1()   結果: alex (<cell at  0x0000020077EFC378 str  object  at  0x00000200674DC340 >,) 返回的結果不是 None 就是閉包

現在有個問題,這個閉包只能在裡邊呼叫啊,外邊的怎麼呼叫呢?

1 2 3 4 5 6 7 8 def  outer():         name  =  "alex"         # 內部函式         def  inner():                 print (name)         return  inner fn  =  outer()    # 訪問外部函式, 獲取到內部函式的函式地址 fn()     # 訪問內部函式       

這樣就實現了外部訪問,那如果多層巢狀呢?很簡單,只需要一層一層的往外層返回就行了  

1 2 3 4 5 6 7 def  func1():         def  func2():                 def  func3():                     print ( "嘿嘿" )                return  func3       return  func2 func1()()()       

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

1 2 3 4 5 6 7 8 9 10 def func():      name =  'alex'            def foo():          print(name)      return  foo   msg = func()   msg() #這樣的話就是將name= 'alex' 存放在一個常駐的記憶體中,並且外界不能修改

閉包的作用就是讓一個變數能夠常駐記憶體,供後面的程式使用  

回到頂部

迭代器

我們之前一直在用可迭代物件進行操作,那麼到底什麼是可迭代物件.我們現在就來討論討論可迭代物件.首先我們先回顧下我們

熟知的可迭代物件有哪些:

str  list   tuple  dic  set  那為什麼我們稱他們為可迭代物件呢?因為他們都遵循了可迭代協議,那什麼又是可迭代協議呢.首先我們先看一段錯誤的程式碼:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 對的 =  'abc' for  in  s:      print (i)   結果: a b c   錯的 for  in  123 :      print (i)   結果 Traceback (most recent call last):    File  "D:/python_object/二分法.py" , line  62 in  <module>      for  in  123 : TypeError:  'int'  object  is  not  iterable

  

注意看報錯資訊,報錯資訊中有這樣一句話: 'int' object is not iterable 翻譯過來就是整數型別物件是不可迭代的.

iterable表示可迭代的.表示可迭代協議 那麼如何進行驗證你的資料型別是否符合可迭代協議.我們可以通過dir函式來檢視類中定義好的

所有方法

1 2 3 =  'abc' print ( dir (a))   # dir檢視物件的方法和函式 # 在列印結果中尋找__iter__ 如果存在就表示當前的這個型別是個可迭代物件

我們剛剛測了字串中是存在__iter__的,那我們來看看  列表,元祖,字典.集合中是不是有存在__iter__

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 列表 lst  =  [ 1 , 2 ] print ( dir (lst))   # 元祖 tuple  =  ( 1 , 2 ) print ( dir ( tuple ))   # 字典 dic  =  { 'a' : 1 , 'b' : 2 } print ( dir (dic))   # 集合 se  =  { 1 , 2 , 3 , 4 , 4 } print ( dir (se))

是不是發現以上都有__iter__並且還很for迴圈啊,其實也可以這麼說可以for迴圈的就有__iter__方法,包括range

1 print ( dir ( range ))

這是檢視一個物件是否是可迭代物件的第一種方法,我們還可以通過isinstence()函式來檢視一個物件是什麼型別的

1 2 3 4 5 6 7 8 =  [ 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

通過上邊的我們可以確定.如果物件中有__iter__函式,那麼我們認為這個物件遵守了可迭代協議.就可以獲取到相應的迭代器

.這裡的__iter__是幫助我們獲取到物件的迭代器.我們使用迭代器中的__next__()來獲取到一個迭代器的元素,那麼我們之前所講的

for的工作原理到底是什麼? 繼續向下看:

1 2 3 4 5 6 7 8 9 10 =  "我愛北京天安⻔" =  s.__iter__()  # 獲取迭代器 print (c.__next__())  # 使⽤迭代器進⾏迭代. 獲取⼀個元素 我 print (c.__next__())  # 愛 print (c.__next__())  # 北 print (c.__next__())  # 京 print (c.__next__())  # 天 print (c.__next__())  # 安 print (c.__next__())  # ⻔ print (c.__next__())  # StopIteration

for迴圈是不是也可以,並且還不報錯啊,其實上邊就是for的機制,

我們使用while迴圈和迭代器來模擬for迴圈: 必須要會

1 2 3 4 5 6 7 8 9 lst  =  [ 6 , 5 , 4 ] =  lst.__iter__()   while  True :      try :          =  l.__next__()          print (i)      except  StopIteration:          break

注意: 迭代器不能反覆,只能向下執行

總結:        

        Iterable: 可迭代物件. 內部包含__iter__()函式        

        Iterator: 迭代器. 內部包含__iter__() 同時包含__next__().        

迭代器的特點:            

        1. 節省記憶體.            

        2. 惰性機制            

        3. 不能反覆, 只能向下執行.    

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