1. 程式人生 > 其它 >python之生成器與模組

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

結論:

  1. 在函式內部添加了yield關鍵字之後,函式就會變成生成器物件,並且可以呼叫__next__方法。
  2. 當有多個yield關鍵字時,每執行一次__next__方法時函式程式碼會執行到下個yield處並停留。
  3. 如果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

模組

簡介

模組就是一系列功能的結合體,只需要匯入就可以直接使用,它極大的提升了開發效率。比如我自己要實現一個功能可能要寫好幾行程式碼,但是如果模組裡可以實現這個功能,那我可以直接拿來使用。

模組的三種來源方式:

  1. 內建的模組

    這些是python自帶的模組,直接用程式碼匯入就可以使用。

  2. 自定義模組

    這些是自己寫的程式碼封裝成模組,可以自己使用或釋出到網上

  3. 第三方模組

    這些是由別人釋出到網上的,我們可以下載過來使用

模組的四種表現形式:

  1. 使用python程式碼編寫的py檔案
  2. 多個py檔案組成的資料夾,也可以稱為包
  3. 已被編譯為共享庫或DLL的c或C++擴充套件(瞭解)
  4. 使用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方法匯入模組後,可以直接使用模組內部的名稱,所以這時候就需要避免出現重名的情況。

圖解

補充

  1. 匯入模組時可以給模組起別名
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()
  1. 匯入全部名稱
from md import *
"""如果模組檔案中使用了__all__限制可以使用的名字,那麼*號就會失效,只能使用__all__後面列舉的名字"""
# 在md.py檔案中
__all__ = ['name']
# 這時如果使用from md import *只能使用name變數
  1. 建議

匯入個模組時,可以把有相似功能的模組使用同一個import匯入,如果沒有建議分開匯入。