1. 程式人生 > 其它 >今日學習內容總結1.7

今日學習內容總結1.7

今日學習內容總結

      在昨日的學習中,我們通過對迭代器,迭代器物件,可迭代物件的瞭解,加長異常處理的實際操作。成功理解了for迴圈的本質。今天就讓我們來學習生成器,以及模組的匯入與使用。

生成器物件

      生成器物件,本質還是迭代器。生成器函式是指在函式體中使用yield表示式僅返回結果的函式。yield表示式僅在定義生成器函式時使用,因此只能用在函式定義的主體中。在函式體中使用yield表示式會使該函式成為生成器函式。當生成器函式被呼叫時,它返回一個稱為生成器的迭代器,該迭代器由python自動生成。然後,生成器控制了生成器函式的執行。因為返回的生成器是一個迭代器,所以生成器函式的執行結果也就可以被迴圈。當生成器的的__next__方法被呼叫時,生成器函式的函式體內的語句開始執行,執行進行到第一個yield表示式時,立即將yield表示式的結果返回給生成器的呼叫者,同時將生成器函式內部的狀態掛起。即保持生成器函式的執行進度,和生成器函式內的區域性狀態:包括區域性變數的當前繫結,指令指標,內部計算棧和任何異常處理的狀態。當生成器的再次呼叫__next__方法來時,生成器函式恢復執行,並再次執行到yield表示式返回結果再保持狀態,直到無法再執行到yield表示式。此時生成器自動丟擲StopIteration異常。

  # 我們先定義一個簡單生成器函式,函式功能返回數字0-9的平方數
  def squares():
      for i in range(10):
          yield i ** 2

  g = squares()

  print(squares)  # <function squares at 0x000001B034A51EA0>
  print(g)  # <generator object squares at 0x000001B034B90CA8>


  # 從上面可以看出變數squares是函式型別,變數g是generator型別物件,generator從字面的理解上就是生成器型別。

  for i in g:
      print(i)  
  # 這就實現了我們0-9的平方數的功能

      生成器物件也是節省儲存空間的,特性與迭代器物件一致。但是在其沒有呼叫前,就是一個普通的函式。如果函式體程式碼中含有多個yield關鍵字,執行一次__next__返回後面的值並且讓程式碼停留在yield位置,再次執行__next__基於上次的位置繼續往後執行到下一個yield關鍵字處,如果沒有了再執行也會報錯StopIteration

自定義range方法

      range方法其實是一個可迭代物件。課堂練習:

  # 通過生成器模擬range方法
  def my_rangge(i, j = None, x = 1):
      if not j:
          j = i
          i = 0
      while i < j:
          yield i
          i += x

  for i in my_rangge(1, 10, 2):
      print(i)

  # 寫程式碼的時候一定要記住雞哥說的寫程式碼不要想太多,先搭建主體功能,之後再考慮其他情況。

yield關鍵字作用

      yield關鍵字作用:1.在函式體程式碼中出現,可以將函式變成生成器。2.在執行過程中,可以將後面的值返回出去,類似於return。3.可以暫停程式碼的執行。4.可以接收外界的傳值。

  # yield 的使用和 return 很像,不同的是 yield 會返回一個生成器。
  def squares():
      a = range(3)
      for i in a:
          yield i*i


  res = squares()

  print(res)  # <generator object squares at 0x000001EC183B0CA8>

  for i in res:
      print(i)  # 0  1  4

      上面例子中,呼叫 squares() 返回的是一個生成器,需要對生成器 res進行遍歷,才能得到值。對生成器進行第一遍遍歷時,會執行 squares() 函式中的程式碼直到 yield i*i,這時會返回第一個值,緊接著第二遍遍歷會返回第二個值,直到生成器為空。

生成器表示式

      生成器表達的作用式也是為了節省儲存空間。在後期做程式碼優化時考慮使用。

  res = (i for i in 'jason')
  print(res)  # <generator object <genexpr> at 0x000002440A5B0CA8>
  print(res.__next__())  # j
  print(res.__next__())  # a
  print(res.__next__())  # s

      生成器內部的程式碼只有在呼叫__next__迭代取值的時候才會執行

模組

模組簡介

      模組,簡而言之,在python中,一個檔案(以“.py”為字尾名的檔案)就叫做一個模組,每一個模組在python裡都被看做是一個獨立的檔案。模組讓你能夠有邏輯地組織你的 Python 程式碼段。把相關的程式碼分配到一個模組裡能讓你的程式碼更好用,更易懂。模組能定義函式,類和變數,模組裡也能包含可執行的程式碼。一個模組編寫完畢之後,其他模組直接呼叫,不用再從零開始寫程式碼了,節約了工作時間;避免函式名稱和變數名稱重複,在不同的模組中可以存在相同名字的函式名和變數名,但是,切記,不要和系統內建的模組名稱重複。

      而python之所以牛逼,並且適用於各個行業,很大程度上就是因為模組。很多大佬寫了很多非常牛逼的模組 供python工程師直接使用,而我們在未來需要一個非常複雜的功能需要實現的時候,那麼第一時間不是想著如何去寫,而是去網上找有沒有相應的python模組!!!

      模組的三種來源:1.內建的(python直譯器自帶)。2.第三方的(別人寫的)。3.自定義的(我們自己寫的)。

      模組的四種表現形式:1.使用python編寫的py檔案(也就意味著py檔案也可以稱之為模組:一個py檔案也可以稱之為一個模組)。2.已被編譯為共享庫或DLL的C或C++擴充套件。3.把一系列模組組織到一起的資料夾(資料夾下有一個__init__.py檔案,該資料夾稱之為包)包:一系列py檔案的結合體。4.使用C編寫並連線到python直譯器的內建模組。

      使用模組的原因:1.用別人寫好的模組(內建的,第三方的):典型的拿來主義,極大的提高開發效率。2.使用自己寫的模組(自定義的):當程式比較龐大的時候,你的專案不可能只在一個py中那麼當多個檔案中都需要使用相同的方法的時候 可以將該公共的方法寫到一個py檔案中其他的檔案以模組的形式導過去直接呼叫即可。

模組的匯入方式

      要想使用模組,必須先匯入。而我們匯入模組的方式有兩種:

      匯入方式一

  # import + 句式

      在研究模組的時候,一定要分清楚誰是執行檔案 誰是被匯入檔案(模組)。

      import句式的特點:1.可以通過import後面的模組名點的方式,使用模組中所有的名字。2.並且不會與當前名稱空間中的名字衝突(指名道姓)。

  import a  # a裡面有一個money=1
  money = 666
  a.change()
  print(money)  # 666

      由上圖知,我們a.py和b.py中都有方法1,但是並不會衝突,而我們在b中執行模組a後,會產生這個檔案的全域性名稱空間,執行import句式就會執行a.py裡面的程式碼,指向這個檔案對應的名稱空間。而我們通過a.方法的方式,就可以使用模組名稱空間中的名字。

      匯入方式二

  # from ... import ...
  from a import money  
  print(money)  # 1
  money = 666
  print(money)  # 666

  print(name)  # 報錯 from a import money 只使用模組中的money名字

      from...import的句式會產生名字衝突的問題,在使用的時候 一定要避免名字衝突。使用from...import的句式,只能使用import後面出現的名字。

      圖中詳細說明了from方法的使用原理