1. 程式人生 > 實用技巧 >Python可迭代物件、迭代器和生成器

Python可迭代物件、迭代器和生成器

Python可迭代物件、迭代器和生成器

很多人學習python,不知道從何學起。
很多人學習python,掌握了基本語法過後,不知道在哪裡尋找案例上手。
很多已經做案例的人,卻不知道如何去學習更加高深的知識。
那麼針對這三類人,我給大家提供一個好的學習平臺,免費領取視訊教程,電子書籍,以及課程的原始碼!
QQ群:1097524789

目錄

  • Python可迭代物件、迭代器和生成器
    • 總覽:可迭代物件、迭代器、生成器之間的關係
        • 2.2.1 生成器表示式(元組推導式)
        • 2.2.2 帶有關鍵字yield的函式
      • 3.1 給定一個list和一個指定數字,求這個數字在list中的位置
      • 3.2 給定兩個序列,判定第一個是不是第二個的子序列
      • 3.3 計算0-9數字的平方和
      • 3.4 web自動化測試pytest框架,測試夾具設定前後置條件

總覽:可迭代物件、迭代器、生成器之間的關係

  • 可迭代物件:可以進行for迴圈的都是可迭代物件,原因是其內部實現了一個__iter__方法
  • 迭代器:能夠用next()函式,都是迭代器物件,其內部實現了__iter____next__方法
  • 生成器:元組推導式和函式裡使用yield的函式都是生成器
  • 生成器是一種特殊的迭代器,迭代器也是可迭代物件,可迭代物件可通過iter()函式轉化為成為迭代器
  • 容器(列表,元組,字典,集合)是可迭代物件,可迭代物件呼叫 iter() 函式,可以得到一個迭代器。迭代器可以通過 next() 函式來得到下一個元素,從而支援遍歷。

1.可迭代物件和迭代器

1.1 基礎概念

_iter_()
_next_()

1.2 判斷

from collections.abc import Iterable, Iterator
a = [1, 2, 3]
b = iter(a) # 可迭代物件呼叫內建iter()方法返回一個迭代器
isinstance(a, Iterable)
isinstance(b, Iterator)
isinstance(b, Iterable)

1.3 for迴圈本質

呼叫可迭代物件的_iter_()方法,得到該物件對應的迭代器物件,然後無限呼叫_next_()方法,得到物件中的每一個元素,直到Stopiteration異常,代表迭代器中已無下一個元素,for迴圈自動處理該異常,跳出迴圈。

# 字典的鍵,值,鍵值對都是可迭代物件
for key in {'one':1, 'two':2}:
    print(key)
# 字串是可迭代物件
for char in "123":
    print(char)
# 開啟的text同樣是可迭代物件
for line in open("myfile.txt"):
    print(line, end='')

1.4 不想用for迴圈迭代了,如何使用迭代器?

  1. 先呼叫容器(以字串為例)的iter()函式
  2. 再使用next()內建函式來呼叫__next__()方法
  3. 當元素用盡時,__next__()將引發 StopIteration 異常

1.5 列表推導式

  • []
li = [i for i in range(10)]
print(li)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 每個元素在生成後都會存在記憶體中,如果元素很多,就會佔用很大的儲存空間

迭代器實現一個列表:[i for i in range(1000)]

2. 生成器Generator

2.1 概念

在Python中,我們把一邊迴圈一邊計算的機制,稱為生成器。生成器也是一種迭代器,但由於它們並沒有把所有的值存在記憶體中,而是在執行時生成值,因此只能迭代一次。

使用生成器,可以寫出來更加清晰的程式碼;合理使用生成器,可以降低記憶體佔用、優化程式結構、提高程式速度。

2.2 如何實現和使用?

2.2.1 生成器表示式(元組推導式)

  • ()
ge = (i for i in range(10))
print(li)
# <generator object <genexpr> at 0x7f4f446a21d0>
next(ge)
# 0
  • 生成器表示式可以認為是一種特殊的生成器函式,返回生成器物件,一次只返回一個值

2.2.2 帶有關鍵字yield的函式

  • 程式執行到yied這一行的時候,生成器呼叫next()函式生成一個值,同時暫停程式,直到下次呼叫next()函式時才啟用,從上次離開的位置恢復執行
def reverse(data):
    for index in range(len(data)):
        yield data[index] 
    print("大大")
# reverse('golf'), 此條語句返回一個生成器物件(也是可迭代物件),for迴圈實現遍歷沒毛病
for char in reverse('golf'):
    print(char)
# 輸出
g
o
l
f
大大
# 遍歷方法2
char = reverse('golf') # 返回一個生成器物件,<generator object reverse at 0x7f71c8124250>
print(next(char))
print(next(char))
print(next(char))
print(next(char))
print(next(char))
# 輸出
g
o
l
f
大大
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)

3. 應用舉例

3.1 給定一個list和一個指定數字,求這個數字在list中的位置

# 常規for迴圈遍歷
def index_normal(L, target):
    result = []
    for i, num in enumerate(L):
        if num == target:
            result.append(i)
    return result

print(index_normal([1, 6, 2, 4, 5, 2, 8, 6, 3, 2], 2))

# 使用生成器
def index_generator(L, target):
    for i, num in enumerate(L):
        if num == target:
            yield i
# index_generator會返回一個生成器物件,需要使用list轉換為列表後,才能print輸出
print(list(index_generator([1, 6, 2, 4, 5, 2, 8, 6, 3, 2], 2)))
# 輸出
[2, 5, 9]

3.2 給定兩個序列,判定第一個是不是第二個的子序列

解析:序列就是列表,子序列指的是一個列表的元素在第二個列表中都按順序出現,但是並不必挨在一起

def is_subsequence(a, b): 
    b = iter(b) # 把列表b轉化成一個迭代器
    return all(i in b for i in a) 
    # (i for i in a),將列表a初始化為一個生成器,可以遍歷物件a
    # i in b,判斷生成器next()函式遍歷a的指是否在迭代器b呼叫next()得到的物件中
    # all函式,判斷一個迭代器的元素是否全部為True

print(is_subsequence([1, 3, 5], [1, 2, 3, 4, 5]))
print(is_subsequence([1, 4, 3], [1, 2, 3, 4, 5]))
# 輸出
True
False

3.3 計算0-9數字的平方和

sum(i*i for i in range(10))  
# 285

3.4 web自動化測試pytest框架,測試夾具設定前後置條件

@pytest.fixture(scope="class")
def browser():
    """啟動和關閉瀏覽器"""
    # 初始化瀏覽器
    driver = webdriver.Chrome()
    # 設定隱式等待
    driver.implicitly_wait(10)
    # 瀏覽器頁面最大化
    driver.maximize_window()
    # 返回一個瀏覽器物件
    yield driver
    driver.quit()