python之生成器與模組
生成器物件
生成器物件其實本質還是迭代器,只不過這個迭代器的內容可以由我們直接來定義了,所以它也可以稱為自定義迭代器。
先來看一段程式碼:
def index():
print('abc')
yield
print(index()) # 輸出:<generator object index at 0x000001DEEAF00200>
可以看到,在加了關鍵字yield之後,函式變成了生成器物件了。如果想要執行函式裡的程式碼,就需要使用__next__()方法。
def index():
print('abc')
yield
res = index()
res.__next__() # 輸出:abc
多個yield
def index():
print('abc')
yield
print('def')
yield
print('gh')
yield
res = index()
res.__next__() # 輸出:abc
res.__next__() # 輸出:def
res.__next__() # 輸出:gh
在yield後也可以跟上一個值
def index(): print('abc') yield 123 print('def') yield 456 res = index() r1 = res.__next__() # 輸出:abc print(r) # 輸出:123 r2 = res.__next__() # 輸出:def print(r) # 輸出:456
結論:
- 在函式內部添加了yield關鍵字之後,函式就會變成生成器物件,並且可以呼叫__next__方法。
- 當有多個yield關鍵字時,每執行一次__next__方法時函式程式碼會執行到下個yield處並停留。
- 如果yield後跟上了一個值,則執行__next__方法時會返回yield後的值。
補充:yield關鍵字的作用
除了以上的作用外,yield還可以接收外界的傳值
def eat(name): print(f'{name}準備乾飯') while True: food = yield print(f'{name}正在吃{food}') res = eat('jason') # 使用send方法前需要呼叫一次__next__啟動 res.__next__() # 輸出:jason準備乾飯 # 使用send方法給yield傳值 res.send('kfc') # 輸出:jason正在吃kfc res.send('米飯') # 輸出:jason正在吃米飯
自定義range方法
在瞭解完生成器物件後,這時候我們就可以自己定義一個和range一樣功能的方法了。
先實現兩個引數的情況:
def my_range(start, end):
"""
start: 起步位置
end: 結束位置
"""
# 如果start一直累加後值等於end則退出迴圈
while start < end:
yield start
# 每被執行一次__next__方法起始位置加1
start += 1
for i in my_range(1, 4):
print(i)
實現了兩個引數後,我們可以開始解決一個引數的情況
def my_range(start, end=None):
"""
start: 起步位置
end: 結束位置,預設為空值
"""
# 如果沒有給end傳值,說明只有一個引數,取值範圍為[0,start)
if not end:
end = start
start = 0
# 如果start一直累加後值等於end則退出迴圈
while start < end:
yield start
# 每被執行一次__next__方法起始位置加1
start += 1
for i in my_range(1, 4):
print(i)
最後解決三個引數的情況
def my_range(start, end=None, step=1):
"""
start: 起步位置
end: 結束位置,預設為空值
step:步長,預設為1
"""
# 如果沒有給end傳值,說明只有一個引數,取值範圍為[0,start)
if not end:
end = start
start = 0
# 如果start一直累加後值等於end則退出迴圈
while start < end:
yield start
# 每被執行一次__next__方法起始位置加步長
start += step
for i in my_range(1, 4):
print(i)
生成器表示式
直入主題,生成器結構
res = (i for i in 'jason')
print(res) # 輸出:<generator object <genexpr> at 0x000002AC49CF0200>
"""可以看到,它並不會像列表生成式一樣直接輸出"""
"""因為生成器內部的程式碼只有在呼叫__next__迭代取值的時候才會執行"""
print(res.__next__()) # 輸出:j
print(res.__next__()) # 輸出:a
模組
簡介
模組就是一系列功能的結合體,只需要匯入就可以直接使用,它極大的提升了開發效率。比如我自己要實現一個功能可能要寫好幾行程式碼,但是如果模組裡可以實現這個功能,那我可以直接拿來使用。
模組的三種來源方式:
-
內建的模組
這些是python自帶的模組,直接用程式碼匯入就可以使用。
-
自定義模組
這些是自己寫的程式碼封裝成模組,可以自己使用或釋出到網上
-
第三方模組
這些是由別人釋出到網上的,我們可以下載過來使用
模組的四種表現形式:
- 使用python程式碼編寫的py檔案
- 多個py檔案組成的資料夾,也可以稱為包
- 已被編譯為共享庫或DLL的c或C++擴充套件(瞭解)
- 使用C編寫並連結到python直譯器的內建模組(瞭解)
模組的匯入方式
第一種:import ...
語法結構:
import 模組1, 模組2, ...
這種匯入方式可以使用模組內部的變數和方法,一個模組只會被匯入一次,不管你執行了多少次import。
案例一:
建立一個md.py檔案
name = '來自md.py'
print(name)
建立一個main.py檔案
import md
執行main.py檔案,此時會輸出
來自md.py
說明在導模組時,會執行被匯入模組的內部程式碼。
案例二:
建立一個md.py檔案
name = '來自md.py的name變數'
def index():
print('來自md.py的index函式')
建立一個main.py檔案
import md
name = '來自main.py的name變數'
print(name)
print(md.name)
def index():
print('來自main.py的index函式')
index()
md.index()
執行main.py檔案,此時會輸出
來自main.py的name變數
來自md.py的name變數
來自main.py的index函式
來自md.py的index函式
說明匯入模組後,想要模組內部變數和函式需要使用模組加點的方式,直接使用只會從當前檔案尋找。
圖解:
第二種:from ... import ...
語法結構:
from 模組名 import 名稱1,名稱2,...
這種方式使用模組內部的名稱可以不需要用模組加點的方式了,可以直接使用。
案例一:
建立一個md.py檔案
name = '來自md.py'
print(name)
建立一個main.py檔案
from md import name
執行main.py檔案,此時會輸出
來自md.py
說明在導模組時,會執行被匯入模組的內部程式碼。
案例二:
建立一個md.py檔案
name = '來自md.py'
def index():
print('來自md.py的index函式')
建立一個main.py檔案
from md import name, index
print(name)
index()
執行main.py檔案,此時會輸出
來自md.py
來自md.py的index函式
說明使用from + import方法匯入模組後,可以直接使用模組內部的名稱,所以這時候就需要避免出現重名的情況。
圖解
補充
- 匯入模組時可以給模組起別名
import time as t
t.sleep(3) # 等價於time.sleep(3)
from md import name as n, index as x
print(n) # 等價於print(name)
x() # 等價於index()
- 匯入全部名稱
from md import *
"""如果模組檔案中使用了__all__限制可以使用的名字,那麼*號就會失效,只能使用__all__後面列舉的名字"""
# 在md.py檔案中
__all__ = ['name']
# 這時如果使用from md import *只能使用name變數
- 建議
匯入個模組時,可以把有相似功能的模組使用同一個import匯入,如果沒有建議分開匯入。