欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python通過for循環(huán)理解迭代器和生成器實(shí)例詳解

 更新時(shí)間:2019年02月16日 10:05:51   作者:Waspvae  
這篇文章主要介紹了Python通過for循環(huán)理解迭代器和生成器,結(jié)合實(shí)例形式詳細(xì)分析了迭代器和生成器的概念、原理、使用方法及相關(guān)操作技巧,需要的朋友可以參考下

本文實(shí)例講述了Python通過for循環(huán)理解迭代器和生成器。分享給大家供大家參考,具體如下:

迭代器

可迭代對象

通過 for…in… 循環(huán)依次拿到數(shù)據(jù)進(jìn)行使用的過程稱為遍歷,也叫迭代。我們把可以通過 for…in… 語句迭代讀取數(shù)據(jù)的對象稱之為可迭代對象。

- 通過 isinstance()可以判斷一個(gè)對象是否可以迭代

# 判斷列表
print(isinstance([], Iterable)

打印結(jié)果為 True 即為可迭代對象。

- 自定義一個(gè)能容納數(shù)據(jù)的類,測試該類的可迭代性

import collections
class MyClassmate(object):
  def __init__(self):
    self.names = []
  def add(self, name):
    self.names.append(name)
# 創(chuàng)建 MyClassmate對象
my_classmate = MyClassmate()
my_classmate.add("小王")
my_classmate.add("小李")
my_classmate.add("小張")
# 判斷MyClassmate是否為可迭代對象
print("是否為可迭代對象:",isinstance(my_classmate, collections.Iterable))
# 迭代數(shù)據(jù)
for temp in my_classmate:
  print(temp)

運(yùn)行結(jié)果:

是否為可迭代對象: False
Traceback (most recent call last):
    for temp in my_classmate:
TypeError: 'MyClassmate' object is not iterable

封裝一個(gè)可以存放多條數(shù)據(jù)的類型是不可迭代的

何為可迭代對象

  • 我們分析對可迭代對象進(jìn)行迭代使用的過程,發(fā)現(xiàn)每迭代一次(即在 for…in… 中每循環(huán)一次)都會返回對象中的下一條數(shù)據(jù),一直向后讀取數(shù)據(jù)直到迭代了所有數(shù)據(jù)后結(jié)束。那么,在這個(gè)過程中就應(yīng)該有一個(gè)"人"去記錄每次訪問到了第幾條數(shù)據(jù),以便每次迭代都可以返回下一條數(shù)據(jù)。我們把這個(gè)能幫助我們進(jìn)行數(shù)據(jù)迭代的"人"稱為迭代器 (Iterator)。
  • 可迭代對象的本質(zhì)就是提供一個(gè)這樣的中間"人"即迭代器幫助我們對其進(jìn)行迭代遍歷使用。
  • 可迭代對象通過__iter__方法向我們提供一個(gè)迭代器,在迭代一個(gè)可迭代對象的時(shí)候,實(shí)際上就是先獲取該對象提供的一個(gè)迭代器,然后通過這個(gè)迭代器來依次獲取對象中的每一個(gè)數(shù)據(jù).

1.可迭代對象的本質(zhì)就是提供一個(gè)這樣的中間"人"即迭代器幫助我們對其進(jìn)行迭代遍歷使用

2.可迭代對象是一個(gè)具備了__iter__方法的對象,通過__iter__方法獲取可迭代對象的迭代器

from collections import Iterable
class MyClassmate(object):
  def __init__(self):
    self.names = []
  def add(self, name):
    self.names.append(item)
  def __iter__(self):
    """空實(shí)現(xiàn)該方法"""
    return None
# 創(chuàng)建 MyClassmate對象
my_classmate = MyClassmate()
my_classmate.add("小王")
my_classmate.add("小李")
my_classmate.add("小張")
# 判斷MyClassmate是否為可迭代對象
print(isinstance(my_classmate, Iterable))

運(yùn)行結(jié)果:

是否為可迭代對象: True

這回測試發(fā)現(xiàn)添加了__iter__方法的my_classmate對象已經(jīng)是一個(gè)可迭代對象了。

iter() 函數(shù)與 next() 函數(shù)

list、tuple 等都是可迭代對象,我們可以通過 iter() 函數(shù)獲取這些可迭代對象的迭代器。然后我們可以對獲取到的迭代器不斷使用 next() 函數(shù)來獲取下一條數(shù)據(jù)。

li = [11, 22, 33, 44, 55]
# 通過iter() 取得可迭代對象的迭代器
iterator = iter(li)
# 通過next()函數(shù)取得iterator迭代器指向的下一個(gè)值
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))
print(next(iterator))

1.iter(iterable) 函數(shù)是把可迭代對象的迭代器取出來,內(nèi)部是調(diào)用可迭代對象的__iter__方法,來取得迭代器的

2.next(iterator) 函數(shù)是通過迭代器取得下一個(gè)位置的值,內(nèi)部是調(diào)用迭代器對象的__next__方法,來取得下一個(gè)位置的值

注意: 當(dāng)我們已經(jīng)迭代完最后一個(gè)數(shù)據(jù)之后,再次調(diào)用 next() 函數(shù)會拋出 StopIteration 的異常,來告訴我們所有數(shù)據(jù)都已迭代完成,不用再執(zhí)行 next() 函數(shù)了。

迭代器

我們要想構(gòu)造一個(gè)迭代器,就要實(shí)現(xiàn)它的__next__ 方法。但這還不夠,python 要求迭代器本身也是可迭代的,所以我們還要為迭代器實(shí)現(xiàn)__iter__ 方法,而 __iter__ 方法要返回一個(gè)迭代器,迭代器自身正是一個(gè)迭代器,所以迭代器的 __iter__ 方法返回自身即可。

一個(gè)實(shí)現(xiàn)了 __iter__ 方法和 __next__ 方法的對象,就是迭代器,迭代器同時(shí)也是一個(gè)可迭代對象.

import collections
class MyClassmate(object):
  def __init__(self):
    # 聲明一個(gè)列表
    self.names = []
    # 記錄迭代器迭代的位置, 默認(rèn)是0 ,即從起始位置開始
    self.current = 0
  def add(self, name):
    self.names.append(name)
  def __iter__(self):
    """通過該方法取得迭代器對象"""
    return self
  def __next__(self):
    """取得下一個(gè)迭代的值"""
    if self.current < len(self.names):
      name = self.names[self.current]
      self.current += 1
      return name
    else:
      raise StopIteration
# 創(chuàng)建MyClassmate實(shí)例
my_classmate = MyClassmate()
my_classmate.add("小王")
my_classmate.add("小李")
my_classmate.add("小張")
# 測試MyList是不是可迭代對象
print(isinstance(my_classmate, collections.Iterable))
# 遍歷數(shù)據(jù)
for name in my_classmate:
  print(name)

for…in… 循環(huán)的本質(zhì)

for item in Iterable 循環(huán)的本質(zhì)就是先通過iter()函數(shù)獲取可迭代對象 Iterable 的迭代器,然后對獲取到的迭代器不斷調(diào)用 next() 方法來獲取下一個(gè)值并將其賦值給 item,當(dāng)遇到 StopIteration 的異常后循環(huán)結(jié)束 (for…in..會自動(dòng)處理 StopIteration 異常)。

生成器

生成器

生成器是一種特殊的迭代器,它比迭代器更優(yōu)雅

創(chuàng)建生成器的方法

1.將列表生成式的 [] 改成 ()

# 參考列表生成式
L=[x*2 for x in range(6)]
print(L)
# 把[] 改為() :就是一個(gè)簡單的列表生成器
G=(x*2 for x in range(6))
# 輸出的是生成器對象
print(G)
print("通過next()函數(shù)取得下一個(gè)值")
print(next(G))
print(next(G))
print(next(G))
print(next(G))
print(next(G))
print(next(G))
# 創(chuàng)建一個(gè)簡單生成器,通過 for來遍歷
G=(x*2 for x in range(6))
print("通過for 迭代的結(jié)果:")
for num in G:
  print(num)

運(yùn)行結(jié)果:

[0, 2, 4, 6, 8, 10]
<generator object <genexpr> at 0x7ff7f8bbd5c8>
通過next()函數(shù)取得下一個(gè)值
0
2
4
6
8
10
通過for 迭代的結(jié)果:
0
2
4
6
8
10

2.通過關(guān)鍵字 yield 實(shí)現(xiàn)生成器

def fib(n):
  current_index = 0
  num1, num2 = 0, 1
  while current_index < n:
    # print(num1) # 打印斐波那契數(shù)列
    """
     1. 假如函數(shù)中有yield,則不再是函數(shù),而是生成器
     2. yield 會產(chǎn)生一個(gè)斷點(diǎn)
     3. 假如yield后面緊接著一個(gè)數(shù)據(jù),就會把數(shù)據(jù)返回,
      作為next()函數(shù)或者for ...in...迭代出的下一個(gè)值
    """
    yield num1
    num1, num2 = num2, num1 + num2
    current_index += 1
if __name__ == '__main__':
  # 假如函數(shù)中有yield,則不再是函數(shù),而是一個(gè)生成器
  gen = fib(5)
  #  生成器是一種特殊的迭代器
  for num in gen:
    print(num)
  # 也可以用 next() 函數(shù)取下一個(gè)值

在使用生成器實(shí)現(xiàn)的方式中,我們將原本在迭代器__next__方法中實(shí)現(xiàn)的基本邏輯放到一個(gè)函數(shù)中來實(shí)現(xiàn),但是將打印輸出方式換成 yield,此時(shí)新定義的函數(shù)便不再是函數(shù),而是一個(gè)生成器了。簡單來說:只要在函數(shù)中有 yield 關(guān)鍵字,就稱為生成器。

此時(shí)按照調(diào)用函數(shù)的方式( 案例中為 gen = fib(5) )使用生成器就不再是執(zhí)行函數(shù)體了,而是會返回一個(gè)生成器對象( 案例中為 gen ),然后就可以按照使用迭代器的方式來使用生成器了。

使用 send() 喚醒

def gen():
  i = 0
  while i < 5:
    temp = yield i
    print(temp)
    i += 1
if __name__ == '__main__':
  # 取得生成器對象
  obj = gen()
  # 使用next()喚醒生成器
  print(next(obj))
  print(next(obj))
  # 使用send喚醒生成器 ,在喚醒的同時(shí)向斷點(diǎn)處傳入一個(gè)附加數(shù)據(jù)
  print(obj.send("haha"))
  # 使用next()喚醒生成器
  print(next(obj))
  # 使用send喚醒生成器 ,在喚醒的同時(shí)向斷點(diǎn)處傳入一個(gè)附加數(shù)據(jù)
  print(obj.send("python"))

運(yùn)行結(jié)果:

0
None
1
haha
2
None
3
python

我們除了可以使用 next() 函數(shù)來喚醒生成器繼續(xù)執(zhí)行外,還可以使用 send() 函數(shù)來喚醒執(zhí)行。使用 send() 函數(shù)的一個(gè)好處是可以在喚醒的同時(shí)向斷點(diǎn)處傳入一個(gè)附加數(shù)據(jù)。

總結(jié)

1. 假如函數(shù)中有 yield,則不再是函數(shù),而是生成器
2. yield 會產(chǎn)生一個(gè)斷點(diǎn),暫停函數(shù),保存狀態(tài)
3. 假如yield后面緊接著一個(gè)數(shù)據(jù),就會把數(shù)據(jù)返回,作為 next() 函數(shù)或者 for …in… 迭代出的下一個(gè)值
4. 可以通過 next() 喚醒生成器,讓生成器從斷點(diǎn)處繼續(xù)執(zhí)行

send與next喚醒生成器不同:

1. send 與next都可以喚醒生成器,但send(value)可以傳值給生成器的斷點(diǎn)處
2. 使用:

next(generator)
generator.send("你好")

3. generator.send(None)等價(jià)于next(generator)
4. 注意: 第一次喚醒生成器時(shí),假如使用 send,則只能傳 None,因?yàn)閯傞_始執(zhí)行生成器時(shí),是沒有斷點(diǎn)的

- 解析

temp = yield num
generator.send("你好")

temp = yield num 為賦值語句,當(dāng)看到等號時(shí), 一定是等號左邊先運(yùn)行完,再賦值給等號右邊

而程序運(yùn)行到 yield num 時(shí),會先返回一個(gè)值,也就是此時(shí)的 num ,然后將 send()里的參數(shù)傳給 yield num,進(jìn)而賦值給 temp

希望本文所述對大家Python程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • pycharm 如何縮進(jìn)和SQL亂碼及SQL包含變量

    pycharm 如何縮進(jìn)和SQL亂碼及SQL包含變量

    這篇文章主要介紹了pycharm 如何縮進(jìn)和SQL亂碼及SQL包含變量,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Python存儲List數(shù)據(jù)到文件(text/csv/excel)幾種常見方法

    Python存儲List數(shù)據(jù)到文件(text/csv/excel)幾種常見方法

    在數(shù)據(jù)分析中經(jīng)常需要從csv格式的文件中存取數(shù)據(jù)以及將數(shù)據(jù)寫書到csv文件中,下面這篇文章主要給大家介紹了關(guān)于Python存儲List數(shù)據(jù)到文件(text/csv/excel)的幾種常見方法,需要的朋友可以參考下
    2024-02-02
  • python常見進(jìn)制轉(zhuǎn)換方法示例代碼

    python常見進(jìn)制轉(zhuǎn)換方法示例代碼

    Python為我們提供了強(qiáng)大的內(nèi)置函數(shù)和格式化數(shù)字的方法去實(shí)現(xiàn)進(jìn)制轉(zhuǎn)換的功能,下面這篇文章主要給大家介紹了關(guān)于python常見進(jìn)制轉(zhuǎn)換方法的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • python3 dict ndarray 存成json,并保留原數(shù)據(jù)精度的實(shí)例

    python3 dict ndarray 存成json,并保留原數(shù)據(jù)精度的實(shí)例

    今天小編就為大家分享一篇python3 dict ndarray 存成json,并保留原數(shù)據(jù)精度的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • Pandas實(shí)現(xiàn)groupby分組統(tǒng)計(jì)的實(shí)踐

    Pandas實(shí)現(xiàn)groupby分組統(tǒng)計(jì)的實(shí)踐

    本文主要介紹了Pandas實(shí)現(xiàn)groupby分組統(tǒng)計(jì)的實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • django channels使用和配置及實(shí)現(xiàn)群聊

    django channels使用和配置及實(shí)現(xiàn)群聊

    本文主要介紹了django channels使用和配置及實(shí)現(xiàn)群聊,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • PyCharm在新窗口打開項(xiàng)目的方法

    PyCharm在新窗口打開項(xiàng)目的方法

    今天小編就為大家分享一篇PyCharm在新窗口打開項(xiàng)目的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • python uuid模塊使用實(shí)例

    python uuid模塊使用實(shí)例

    這篇文章主要介紹了python uuid模塊使用實(shí)例,本文給出簡單使用示例,講解uuid1、uuid3、 uuid4、 uuid5這幾個(gè)方法,需要的朋友可以參考下
    2015-04-04
  • python將unicode和str互相轉(zhuǎn)化的實(shí)現(xiàn)

    python將unicode和str互相轉(zhuǎn)化的實(shí)現(xiàn)

    這篇文章主要介紹了python將unicode和str互相轉(zhuǎn)化的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • Python 字符串、列表、元組的截取與切片操作示例

    Python 字符串、列表、元組的截取與切片操作示例

    這篇文章主要介紹了Python 字符串、列表、元組的截取與切片操作,結(jié)合實(shí)例形式分析了Python針對字符串、列表、元組的截取與切片相關(guān)操作技巧,需要的朋友可以參考下
    2019-09-09

最新評論