在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ Python生成器
Python異常處理
Python循環(huán)
Python基本運(yùn)算符
Python網(wǎng)絡(luò)編程(Sockets)
Python可以開發(fā)哪些程序?
Python XML解析和處理
Python數(shù)字
Python函數(shù)
Python變量類型
Python os模塊方法
Python迭代器
Python安裝和環(huán)境配置
Python構(gòu)造函數(shù)
Python文件對象方法
Python日期和時(shí)間
Python的歷史
Python生成器
Python+MySQL數(shù)據(jù)庫操作(PyMySQL)
Python命令行參數(shù)
Python元組
Python發(fā)送郵件
Python列表
Python文件讀寫
Python教程
Python面向?qū)ο螅惡蛯ο螅?/span>
Python多線程編程
Python多重繼承
Python決策
Python是什么?
Python快速入門
Python繼承
Python字典
Python字符串
Python操作符重載
Python正則表達(dá)式
Python閉包
Python修飾器
Python功能特點(diǎn)
Python模塊

Python生成器

在本文中,將學(xué)習(xí)如何使用Python生成器來創(chuàng)建迭代,了解它與迭代器和常規(guī)函數(shù)有什么區(qū)別,以及為什么要使用它。

在Python中構(gòu)建迭代器有很多開銷; 必須使用__iter__()__next__()方法實(shí)現(xiàn)一個(gè)類,跟蹤內(nèi)部狀態(tài),當(dāng)沒有值被返回時(shí)引發(fā)StopIteration異常。

Python生成器是創(chuàng)建迭代器的簡單方法。上面提到的所有開銷都由Python中的生成器自動(dòng)處理。

簡單來說,生成器是返回一個(gè)可以迭代的對象(迭代器)的函數(shù)(一次一個(gè)值)。

如何在Python中創(chuàng)建生成器?

在Python中創(chuàng)建生成器是相當(dāng)簡單的。 它使用yield語句而不是return語句來定義,與正常函數(shù)一樣簡單。

如果函數(shù)包含至少一個(gè)yield語句(它可能包含其他yieldreturn語句),那么它將成為一個(gè)生成器函數(shù)。 yieldreturn都將從函數(shù)返回一些值。

不同的是,return語句完全終止函數(shù),但yield語句會(huì)暫停函數(shù)保存其所有狀態(tài),并在以后的連續(xù)調(diào)用中繼續(xù)執(zhí)行(有點(diǎn)像線程掛起的意思)。

生成器函數(shù)與正常函數(shù)的差異

下面列出的是生成器函數(shù)與正常函數(shù)的區(qū)別 -

  • 生成器函數(shù)包含一個(gè)或多個(gè)yield語句。
  • 當(dāng)被調(diào)用時(shí),它返回一個(gè)對象(迭代器),但不會(huì)立即開始執(zhí)行。
  • __iter__()__next__()之類的方法將自動(dòng)實(shí)現(xiàn)。所以可以使用next()迭代項(xiàng)目。
  • 一旦函數(shù)退讓(yields),該函數(shù)將被暫停,并將該控制權(quán)交給調(diào)用者。
  • 局部變量及其狀態(tài)在連續(xù)調(diào)用之間被記住。
  • 最后,當(dāng)函數(shù)終止時(shí),StopIteration會(huì)在進(jìn)一步的調(diào)用時(shí)自動(dòng)引發(fā)。

下面的例子用來說明上述所有要點(diǎn)。 我們有一個(gè)名為my_gen()的生成器函數(shù)和幾個(gè)yield語句。

#!/usr/bin/python3
#coding=utf-8

def my_gen():
    n = 1
    print('This is printed first, n= ', n)
    # Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second, n= ', n)
    yield n

    n += 1
    print('This is printed at last, n= ', n)
    yield n

下面給出了交互式運(yùn)行結(jié)果。 在Python shell中運(yùn)行它們以查看輸出 -

>>> # It returns an object but does not start execution immediately.
>>> a = my_gen()

>>> # We can iterate through the items using next().
>>> next(a)
This is printed first, n = 1
1
>>> # Once the function yields, the function is paused and the control is transferred to the caller.

>>> # Local variables and theirs states are remembered between successive calls.
>>> next(a)
This is printed second, n = 2
2

>>> next(a)
This is printed at last, n = 3
3

>>> # Finally, when the function terminates, StopIteration is raised automatically on further calls.
>>> next(a)
Traceback (most recent call last):
...
StopIteration
>>> next(a)
Traceback (most recent call last):
...
StopIteration

在上面的例子中需要注意的是,在每個(gè)調(diào)用之間函數(shù)會(huì)保持住變量n的值。
與正常函數(shù)不同,當(dāng)函數(shù)產(chǎn)生時(shí),局部變量不會(huì)被銷毀。 此外,生成器對象只能重復(fù)一次。

要重新啟動(dòng)該過程,需要使用類似于a = my_gen()的方法創(chuàng)建另一個(gè)生成器對象。

注意:最后要注意的是,可以直接使用帶有for循環(huán)的生成器。

這是因?yàn)椋?code>for循環(huán)需要一個(gè)迭代器,并使用next()函數(shù)進(jìn)行迭代。 當(dāng)StopIteration被引發(fā)時(shí),它會(huì)自動(dòng)結(jié)束。 請查看這里了解一個(gè)for循環(huán)是如何在Python中實(shí)際實(shí)現(xiàn)的。

# A simple generator function
def my_gen():
    n = 1
    print('This is printed first')
    # Generator function contains yield statements
    yield n

    n += 1
    print('This is printed second')
    yield n

    n += 1
    print('This is printed at last')
    yield n

# Using for loop
for item in my_gen():
    print(item)

當(dāng)運(yùn)行程序時(shí),將輸出結(jié)果為:

This is printed first
1
This is printed second
2
This is printed at last
3

具有循環(huán)的Python生成器

上面的例子沒有什么用,我們研究它只是為了了解在后臺(tái)發(fā)生了什么。通常,生成器功能用具有適當(dāng)終止條件的循環(huán)實(shí)現(xiàn)。

我們舉一個(gè)反轉(zhuǎn)字符串的生成器的例子 -

 length = len(my_str)
    for i in range(length - 1,-1,-1):
        yield my_str[i]

# For loop to reverse the string
# Output:
# o
# l
# l
# e
# h
for char in rev_str("hello"):
     print(char)def rev_str(my_str):

在這個(gè)例子中,使用range()函數(shù)使用for循環(huán)以相反的順序獲取索引。事實(shí)證明,這個(gè)生成函數(shù)不僅可以使用字符串,還可以使用其他類型的列表,元組等迭代。

Python生成器表達(dá)式

使用生成器表達(dá)式,可以輕松創(chuàng)建簡單的生成器。 它使構(gòu)建生成器變得容易。

lambda函數(shù)一樣創(chuàng)建一個(gè)匿名函數(shù),生成器表達(dá)式創(chuàng)建一個(gè)匿名生成函數(shù)。生成器表達(dá)式的語法與Python中的列表解析類似。 但方圓[]替換為圓括號(hào)()

列表推導(dǎo)和生成器表達(dá)式之間的主要區(qū)別是:列表推導(dǎo)產(chǎn)生整個(gè)列表,生成器表達(dá)式一次生成一個(gè)項(xiàng)目。

它們是處理方式是懶惰的,只有在被要求時(shí)才能生產(chǎn)項(xiàng)目。 因此,生成器表達(dá)式的存儲(chǔ)器效率高于等效列表的值。

# Initialize the list
my_list = [1, 3, 6, 10]

# square each term using list comprehension
# Output: [1, 9, 36, 100]
[x**2 for x in my_list]

# same thing can be done using generator expression
# Output: <generator object <genexpr> at 0x0000000002EBDAF8>
(x**2 for x in my_list)

我們可以看到,生成器表達(dá)式?jīng)]有立即生成所需的結(jié)果。 相反,它返回一個(gè)發(fā)生器對象,并根據(jù)需要生成項(xiàng)目。

# Intialize the list
my_list = [1, 3, 6, 10]

a = (x**2 for x in my_list)
# Output: 1
print(next(a))

# Output: 9
print(next(a))

# Output: 36
print(next(a))

# Output: 100
print(next(a))

# Output: StopIteration
next(a)

生成器表達(dá)式可以在函數(shù)內(nèi)部使用。當(dāng)以這種方式使用時(shí),圓括號(hào)可以丟棄。

>>> sum(x**2 for x in my_list)
146

>>> max(x**2 for x in my_list)
100

為什么在Python中使用生成器?

有幾個(gè)原因使得生成器成為有吸引力。

1. 容易實(shí)現(xiàn)

與其迭代器類相比,發(fā)生器可以以清晰簡潔的方式實(shí)現(xiàn)。 以下是使用迭代器類來實(shí)現(xiàn)2的冪次序的例子。

class PowTwo:
    def __init__(self, max = 0):
        self.max = max

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n > self.max:
            raise StopIteration

        result = 2 ** self.n
        self.n += 1
        return result

上面代碼有點(diǎn)長,可以使用一個(gè)生成器函數(shù)實(shí)現(xiàn)同樣的功能。

def PowTwoGen(max = 0):
    n = 0
    while n < max:
        yield 2 ** n
        n += 1

因?yàn)?,生成器自?dòng)跟蹤的細(xì)節(jié),它更簡潔,更干凈。

2.內(nèi)存高效

返回序列的正常函數(shù)將在返回結(jié)果之前會(huì)在內(nèi)存中的創(chuàng)建整個(gè)序列。如果序列中的項(xiàng)目數(shù)量非常大,這可是要消耗內(nèi)存的。

序列的生成器實(shí)現(xiàn)是內(nèi)存友好的,并且是推薦使用的,因?yàn)樗淮蝺H產(chǎn)生一個(gè)項(xiàng)目。

3. 表未無限流

生成器是表示無限數(shù)據(jù)流的絕佳媒介。 無限流不能存儲(chǔ)在內(nèi)存中,由于生成器一次只能生成一個(gè)項(xiàng)目,因此可以表示無限數(shù)據(jù)流。

以下示例可以生成所有偶數(shù)(至少在理論上)。

def all_even():
    n = 0
    while True:
        yield n
        n += 2

4.管道生成器

生成器可用于管理一系列操作,下面使用一個(gè)例子說明。

假設(shè)我們有一個(gè)快餐連鎖店的日志文件。 日志文件有一列(第4列),用于跟蹤每小時(shí)銷售的比薩餅數(shù)量,我們想算出在5年內(nèi)銷售的總薩餅數(shù)量。

假設(shè)一切都是字符串,不可用的數(shù)字標(biāo)記為“N / A”。 這樣做的生成器實(shí)現(xiàn)可以如下。

with open('sells.log') as file:
    pizza_col = (line[3] for line in file)
    per_hour = (int(x) for x in pizza_col if x != 'N/A')
    print("Total pizzas sold = ",sum(per_hour))

這種管道的方式是更高效和易于閱讀的。