今日學習內容總結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方法的使用原理