亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

流暢的python讀書筆記-第十四章-可迭代的對(duì)象、迭代器和生成器

kohoh_ / 773人閱讀

摘要:可迭代的對(duì)象迭代器和生成器理念迭代是數(shù)據(jù)處理的基石??傻膶?duì)象與迭代器的對(duì)比從可迭代的對(duì)象中獲取迭代器標(biāo)準(zhǔn)的迭代器接口有兩個(gè)方法。此外,也沒有辦法還原迭代器。最終,函數(shù)的定義體返回時(shí),外層的生成器對(duì)象會(huì)拋出異常這一點(diǎn)與迭代器協(xié)議一致。

可迭代的對(duì)象、迭代器和生成器 理念

迭代是數(shù)據(jù)處理的基石。掃描內(nèi)存中放不下的數(shù)據(jù)集時(shí),我們要找到一種惰性獲取數(shù)據(jù)
項(xiàng)的方式,即按需一次獲取一個(gè)數(shù)據(jù)項(xiàng)。這就是迭代器模式(Iterator pattern)。

看個(gè)例子

import re
import reprlib

RE_WORD = re.compile("w+")


class Sentence:
    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)

    def __getitem__(self, index):
        return self.words[index]

    def __len__(self):
        return len(self.words)

    def __repr__(self):
        return "Sentence(%s)" % reprlib.repr(self.text)


s = Sentence(""The time has come," the Walrus said,")
print(s)

for world in s:
    print(world)
for 循環(huán)就是 用到了index, index在__getitem__被用到了
序列可以迭代的原因 iter函數(shù)

解釋器需要迭代對(duì)象 x 時(shí),會(huì)自動(dòng)調(diào)用 iter(x)。

內(nèi)置的 iter 函數(shù)有以下作用。

(1) 檢查對(duì)象是否實(shí)現(xiàn)了 iter 方法,如果實(shí)現(xiàn)了就調(diào)用它,獲取一個(gè)迭代器。

(2) 如果沒有實(shí)現(xiàn) iter 方法,但是實(shí)現(xiàn)了 getitem 方法,Python 會(huì)創(chuàng)建一個(gè)迭代器,嘗試按順序(從索引 0 開始)獲取元素。

(3) 如果嘗試失敗,Python 拋出 TypeError 異常,通常會(huì)提示“C object is not iterable”(C對(duì)象不可迭代),其中 C 是目標(biāo)對(duì)象所屬的類。

可迭代的對(duì)象與迭代器的對(duì)比

Python 從可迭代的對(duì)象中獲取迭代器

標(biāo)準(zhǔn)的迭代器接口有兩個(gè)方法。

next
  返回下一個(gè)可用的元素,如果沒有元素了,拋出 StopIteration 異常。
iter
  返回 self,以便在應(yīng)該使用可迭代對(duì)象的地方使用迭代器,例如在 for 循環(huán)中。

abc.Iterator 類

from  abc import abstractmethod

class Iterator(Iterable):
    __slots__ = ()

    @abstractmethod
    def __next__(self):
        "Return the next item from the iterator. When exhausted, raise StopIteration"
        raise StopIteration

    def __iter__(self):

        return self

    @classmethod
    def __subclasshook__(cls, C):

        if cls is Iterator:
            if (any("__next__" in B.__dict__ for B in C.__mro__) and
                    any("__iter__" in B.__dict__ for B in C.__mro__)):
                return True

        return NotImplemented
如何使用 next(...) 函數(shù)使用迭代器
import re
import reprlib

RE_WORD = re.compile("w+")


class Sentence:
    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)

    def __getitem__(self, index):
        return self.words[index]

    def __len__(self):
        return len(self.words)

    def __repr__(self):
        return "Sentence(%s)" % reprlib.repr(self.text)


# s = Sentence(""The time has come," the Walrus said,")
# print(s)
#
# for world in s:
#     print(world)

## it就是構(gòu)造后的迭代器
## iter(s3) 就是構(gòu)建迭代器的可迭代對(duì)象。
s3 = Sentence("Pig and Pepper")
it = iter(s3)

print(next(it))
print(next(it))
print(next(it))

# 報(bào)錯(cuò) StopIteration
# print(next(it))

print(list(it))

print(list(iter(s3)))
print(list(iter(s3)))

因?yàn)榈髦恍?nextiter 兩個(gè)方法,所以除了調(diào)用 next() 方法,以及捕獲 StopIteration 異常之外,沒有辦法檢查是否還有遺留的元素。

此外,也沒有辦法“還原”迭代器。

如果想再次迭代,那就要調(diào)用 iter(...),傳入之前構(gòu)建迭代器的可迭代對(duì)象。

傳入迭代器本身沒用,因?yàn)榍懊嬲f過 Iterator.__iter__ 方法的實(shí)現(xiàn)方式是
返回實(shí)例本身,所以傳入迭代器無法還原已經(jīng)耗盡的迭代器。

典型的迭代器
import re
import reprlib

RE_WORD = re.compile("w+")


class Sentence:
    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)

    def __repr__(self):
        return "Sentence(%s)" % reprlib.repr(self.text)

    def __iter__(self):
        return SentenceIterator(self.words)


class SentenceIterator:
    def __init__(self, words):
        self.words = words
        self.index = 0

    def __next__(self):
        try:
            word = self.words[self.index]
        except IndexError:
            raise StopIteration()

        self.index += 1
        return word

    def __iter__(self):
        return self

s = Sentence(""The time has come," the Walrus said,")
for word in s:
    print(word)

? 與前一版相比,這里只多了一個(gè) iter 方法。這一版沒有 getitem 方法,為
的是明確表明這個(gè)類可以迭代,因?yàn)閷?shí)現(xiàn)了 iter 方法。
? 根據(jù)可迭代協(xié)議,__iter__ 方法實(shí)例化并返回一個(gè)迭代器。

Sentence 類中,__iter__ 方法調(diào)用 SentenceIterator 類的構(gòu)造方法創(chuàng)建一個(gè)迭代器并將其返回。
為什么 不寫在一起

把Sentence變成迭代器:壞主意

構(gòu)建可迭代的對(duì)象和迭代器時(shí)經(jīng)常會(huì)出現(xiàn)錯(cuò)誤,原因是混淆了二者。

要知道,可迭代的對(duì)象有個(gè) iter 方法,每次都實(shí)例化一個(gè)新的迭代器;
而迭代器要實(shí)現(xiàn) next 方法,返回單個(gè)元素,此外還要實(shí)現(xiàn) iter 方法,返回迭代器本身。

因此,迭代器可以迭代,但是可迭代的對(duì)象不是迭代器。

除了 iter 方法之外,你可能還想在 Sentence 類中實(shí)現(xiàn) next 方法,讓
Sentence 實(shí)例既是可迭代的對(duì)象,也是自身的迭代器。

可是,這種想法非常糟糕。根據(jù)有大量 Python 代碼審查經(jīng)驗(yàn)的 Alex Martelli 所說,這也是常見的反模式。

python的正確解決之道

生成器函數(shù)

import re
import reprlib

RE_WORD = re.compile("w+")


class Sentence:
    def __init__(self, text):
        self.text = text
        self.words = RE_WORD.findall(text)

    def __repr__(self):
        return "Sentence(%s)" % reprlib.repr(self.text)

    def __iter__(self):
        for word in self.words:
            yield word
        return


s = Sentence(""The time has come," the Walrus said,")
for word in s:
    print(word)

? 這個(gè) return 語句不是必要的;這個(gè)函數(shù)可以直接“落空”,自動(dòng)返回。不管有沒有
return 語句,生成器函數(shù)都不會(huì)拋出 StopIteration 異常,而是在生成完全部值之后會(huì)直接退出。
? 不用再多帶帶定義一個(gè)迭代器類!

迭代器其實(shí)是生成器對(duì)象,每次調(diào)用 iter 方法都會(huì)自動(dòng)創(chuàng)建,因?yàn)檫@里的 iter 方法是生成器函數(shù)。
生成器函數(shù)的工作原理

只要 Python 函數(shù)的定義體中有 yield 關(guān)鍵字,該函數(shù)就是生成器函數(shù)。調(diào)用生成器函數(shù)時(shí),會(huì)返回一個(gè)生成器對(duì)象。也就是說,生成器函數(shù)是生成器工廠

def gen_123():  # ?
    yield 1  # ?
    yield 2
    yield 3

print(gen_123)

print(gen_123())

for i in gen_123():  # ?
    print(i)

g = gen_123()  # ?
print(next(g))
print(next(g))
print(next(g))

## 報(bào)錯(cuò) StopIteration
# print(next(g))

? 仔細(xì)看,gen_123 是函數(shù)對(duì)象。
? 為了仔細(xì)檢查,我們把生成器對(duì)象賦值給 g。
? 生成器函數(shù)的定義體執(zhí)行完畢后,生成器對(duì)象會(huì)拋出 StopIteration 異常。

把生成器傳給next(...) 函數(shù)時(shí),生成器函數(shù)會(huì)向前,執(zhí)行函數(shù)定義體中的下一個(gè) yield 語句,返回產(chǎn)出的值,并在函數(shù)定義體的當(dāng)前位置暫停。

最終,函數(shù)的定義體返回時(shí),外層的生成器對(duì)象會(huì)拋出 StopIteration 異?!@一點(diǎn)與迭代器協(xié)議一致。

惰性實(shí)現(xiàn)
import re
import reprlib

RE_WORD = re.compile("w+")


class Sentence:
    def __init__(self, text):
        self.text = text

    def __repr__(self):
        return "Sentence(%s)" % reprlib.repr(self.text)

    def __iter__(self):
        # 返回一個(gè)迭代器
        for match in RE_WORD.finditer(self.text):
            yield match.group()

re.finditer 函數(shù)是 re.findall 函數(shù)的惰性版本,返回的不是列表,而是一個(gè)生成
器,按需生成 re.MatchObject 實(shí)例。

如果有很多匹配,re.finditer 函數(shù)能節(jié)省大量?jī)?nèi)存。
我們要使用這個(gè)函數(shù)讓第 4 版 Sentence 類變得懶惰,即只在需要時(shí)才生成下一個(gè)單詞。

? 不再需要 words 列表。
? finditer 函數(shù)構(gòu)建一個(gè)迭代器,包含 self.text 中匹配 RE_WORD 的單詞,產(chǎn)出
MatchObject 實(shí)例。
? match.group() 方法從 MatchObject 實(shí)例中提取匹配正則表達(dá)式的具體文本。

生成器表達(dá)式

生成器表達(dá)式可以理解為列表推導(dǎo)的惰性版本:不會(huì)迫切地構(gòu)建列表,而是返回一個(gè)生成器,按需惰性生成元素。

def gen_AB():  # ?
    print("start")
    yield "A"
    print("continue")
    yield "B"
    print("end.")


res1 = [x * 3 for x in gen_AB()]

for i in res1:  # ?
    print("-->", i)

res2 = (x * 3 for x in gen_AB())  # ?
print(res2)  # ?

for i in res2:  # ?
    print("-->", i)

? 列表推導(dǎo)迫切地迭代 gen_AB() 函數(shù)生成的生成器對(duì)象產(chǎn)出的元素:"A" 和 "B"。注意,下面的輸出是 start、continue 和 end.。

? 這個(gè) for 循環(huán)迭代列表推導(dǎo)生成的 res1 列表。

? 把生成器表達(dá)式返回的值賦值給 res2。只需調(diào)用 gen_AB() 函數(shù),雖然調(diào)用時(shí)會(huì)返回
一個(gè)生成器,但是這里并不使用。

? res2 是一個(gè)生成器對(duì)象。
? 只有 for 循環(huán)迭代 res2 時(shí),gen_AB 函數(shù)的定義體才會(huì)真正執(zhí)行。
for 循環(huán)每次迭代時(shí)會(huì)隱式調(diào)用 next(res2),前進(jìn)到 gen_AB 函數(shù)中的下一個(gè)yield 語句。

注意,gen_AB 函數(shù)的輸出與 for 循環(huán)中 print 函數(shù)的輸出夾雜在一起。

何時(shí)使用生成器表達(dá)式

根據(jù)我的經(jīng)驗(yàn),選擇使用哪種句法很容易判斷:如果生成器表達(dá)式要分成多行寫,我傾向
于定義生成器函數(shù),以便提高可讀性。此外,生成器函數(shù)有名稱,因此可以重用。

8 另一個(gè)示例:等差數(shù)列生成器
class ArithmeticProgression:
    def __init__(self, begin, step, end=None):  # ?
        self.begin = begin
        self.step = step
        self.end = end  # None -> 無窮數(shù)列


def __iter__(self):
    result = type(self.begin + self.step)(self.begin)  # ?
    forever = self.end is None  # ?
    index = 0
    while forever or result < self.end:  # ?
        yield result  # ?
    index += 1
    result = self.begin + self.step * index  # ?

? 為了提高可讀性,我們創(chuàng)建了 forever 變量,如果 self.end 屬性的值是 None那么forever 的值是 True,因此生成的是無窮數(shù)列。
? 這個(gè)循環(huán)要么一直執(zhí)行下去,要么當(dāng) result 大于或等于 self.end 時(shí)結(jié)束。如果循環(huán)退出了,那么這個(gè)函數(shù)也隨之退出。

在示例 14-11 中的最后一行,我沒有直接使用 self.step 不斷地增加 result,

而是選擇使用 index 變量,把 self.begin 與 self.step 和 index 的乘積加,計(jì)算 result 的各個(gè)值,

以此降低處理浮點(diǎn)數(shù)時(shí)累積效應(yīng)致錯(cuò)的風(fēng)險(xiǎn)。

標(biāo)準(zhǔn)庫里有大量的生成器輪子 page408 深入分析iter函數(shù)

可是,iter 函數(shù)還有一個(gè)鮮為人知的用法:傳入兩個(gè)參數(shù),使用常規(guī)的函數(shù)或任何可調(diào)
用的對(duì)象創(chuàng)建迭代器。

這樣使用時(shí),第一個(gè)參數(shù)必須是可調(diào)用的對(duì)象,用于不斷調(diào)用(沒有參數(shù)),產(chǎn)出各個(gè)值;

第二個(gè)值是哨符,這是個(gè)標(biāo)記值,當(dāng)可調(diào)用的對(duì)象返回這個(gè)值時(shí),觸發(fā)迭代器拋出 StopIteration 異常,而不產(chǎn)出哨符。

iter 函數(shù)擲骰子,直到擲出 1 點(diǎn)為止

from random import randint

def d6():
    return randint(1, 6)

d6_iter = iter(d6, 1)

print(d6_iter)

for roll in d6_iter:
    print(roll)
總結(jié)

迭代器 都有 iter這個(gè)方法(函數(shù)), (每個(gè)都調(diào)用__getitem__做兼容) next()到底.

for每次迭代都是next()

對(duì)付大文件,大內(nèi)存. 先返回迭代器對(duì)象, 在執(zhí)行迭代器的具體 操作

python 用yield 作為生成器的特征

send可以發(fā)送給 那個(gè)狀態(tài)的生成器

iter別的用法 有兩個(gè)參數(shù) 第二個(gè)是哨符 (遇到就停了)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/42044.html

相關(guān)文章

  • 《java 8 實(shí)戰(zhàn)》讀書筆記 -第十四章 函數(shù)式編程技巧

    摘要:但是,最好使用差異化的類型定義,函數(shù)簽名如下其實(shí)二者說的是同一件事。后者的返回值和初始函數(shù)的返回值相同,即。破壞式更新和函數(shù)式更新的比較三的延遲計(jì)算的設(shè)計(jì)者們?cè)趯⒁霑r(shí)采取了比較特殊的方式。四匹配模式語言中暫時(shí)并未提供這一特性,略。 一、無處不在的函數(shù) 一等函數(shù):能夠像普通變量一樣使用的函數(shù)稱為一等函數(shù)(first-class function)通過::操作符,你可以創(chuàng)建一個(gè)方法引用,...

    nemo 評(píng)論0 收藏0
  • 流暢python讀書筆記-第十六章-攜(協(xié))程

    摘要:當(dāng)前狀態(tài)可以使用函數(shù)確定,該函數(shù)會(huì)返回下述字符串中的一個(gè)。解釋器正在執(zhí)行。打印消息,然后協(xié)程終止,導(dǎo)致生成器對(duì)象拋出異常。實(shí)例運(yùn)行完畢后,返回的值綁定到上。 協(xié)程 協(xié)程可以身處四個(gè)狀態(tài)中的一個(gè)。 當(dāng)前狀態(tài)可以使用inspect.getgeneratorstate(...) 函數(shù)確定,該函數(shù)會(huì)返回下述字符串中的一個(gè)。 GEN_CREATED  等待開始執(zhí)行。 GEN_RUNNING  解...

    wanglu1209 評(píng)論0 收藏0
  • 流暢python讀書筆記-第一章Python 數(shù)據(jù)模型

    摘要:第一章數(shù)據(jù)類型隱式方法利用快速生成類方法方法通過下標(biāo)找元素自動(dòng)支持切片操作可迭代方法與如果是一個(gè)自定義類的對(duì)象,那么會(huì)自己去調(diào)用其中由你實(shí)現(xiàn)的方法。若返回,則會(huì)返回否則返回。一個(gè)對(duì)象沒有函數(shù),解釋器會(huì)用作為替代。 第一章 python數(shù)據(jù)類型 1 隱式方法 利用collections.namedtuple 快速生成類 import collections Card = collec...

    tomener 評(píng)論0 收藏0
  • 流暢python讀書筆記-第一章Python 數(shù)據(jù)模型

    摘要:第一章數(shù)據(jù)類型隱式方法利用快速生成字典方法方法通過下標(biāo)找元素自動(dòng)支持切片操作可迭代方法與如果是一個(gè)自定義類的對(duì)象,那么會(huì)自己去調(diào)用其中由你實(shí)現(xiàn)的方法。若返回,則會(huì)返回否則返回。一個(gè)對(duì)象沒有函數(shù),解釋器會(huì)用作為替代。 第一章 python數(shù)據(jù)類型 1 隱式方法 利用collections.namedtuple 快速生成字典 import collections Card = coll...

    FullStackDeveloper 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<