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

鍍金池/ 教程/ Python/ 四、生成器
二、Enum 的源碼
前言
一、Python 模塊簡(jiǎn)介
一、List(列表)
五、匿名函數(shù)
三、什么是元類
二、循環(huán)語句
二、模塊的使用
三、第一個(gè) Python 程序
線程與進(jìn)程
Python
三、條件語句和循環(huán)語句綜合實(shí)例
四、對(duì)象的描述器
三、類的屬性
一、迭代
五、迭代器和生成器綜合例子
六、運(yùn)算符相關(guān)的魔術(shù)方法
一、枚舉類的使用
前言
一、簡(jiǎn)明概述
二、Python 的基本數(shù)據(jù)類型
多線程編程
五、作用域
四、包
四、枚舉的比較
四、Python 中的變量
六、類的多態(tài)
一、Python 中類也是對(duì)象
一、Python 的 Magic Method
前言
四、生成器
一、面向?qū)ο蟮母拍?/span>
五、類的繼承
二、類
二、使用 <code>type()</code> 動(dòng)態(tài)創(chuàng)建類
進(jìn)程
二、set
三、主模塊和非主模塊
一、字典(Dictionary)
前言
前言
前言
前言
四、集成開發(fā)環(huán)境(IDE): PyCharm
前言
四、函數(shù)的參數(shù)
三、lsit 生成式(列表生成式)
四、自定義元類
四、類的方法
二、函數(shù)傳值問題
二、注釋
一、條件語句
一、Python 語法的簡(jiǎn)要說明
三、函數(shù)返回值
三、基本數(shù)據(jù)類型轉(zhuǎn)換
三、屬性的訪問控制
二、Python 的安裝
前言
三、命名規(guī)范
一、Python 自定義函數(shù)的基本步驟
三、自定義類型的枚舉
五、自定義容器(Container)
二、Python 迭代器
前言
二、tuple(元組)
一、Python 簡(jiǎn)介
前言
前言
前言
二、構(gòu)造(<code>__new__</code>)和初始化(<code>__init__</code>)
前言

四、生成器

1、為什么需要生成器

通過上面的學(xué)習(xí),可以知道列表生成式,我們可以直接創(chuàng)建一個(gè)列表。但是,受到內(nèi)存限制,列表容量肯定是有限的。而且,創(chuàng)建一個(gè)包含 1000 萬個(gè)元素的列表,不僅占用很大的存儲(chǔ)空間,如果我們僅僅需要訪問前面幾個(gè)元素,那后面絕大多數(shù)元素占用的空間都白白浪費(fèi)了。

所以,如果列表元素可以按照某種算法推算出來,那我們是否可以在循環(huán)的過程中不斷推算出后續(xù)的元素呢?這樣就不必創(chuàng)建完整的 list,從而節(jié)省大量的空間。在 Python 中,這種一邊循環(huán)一邊計(jì)算的機(jī)制,稱為生成器:generator。

在 Python 中,使用了 yield 的函數(shù)被稱為生成器(generator)。

跟普通函數(shù)不同的是,生成器是一個(gè)返回迭代器的函數(shù),只能用于迭代操作,更簡(jiǎn)單點(diǎn)理解生成器就是一個(gè)迭代器。

在調(diào)用生成器運(yùn)行的過程中,每次遇到 yield 時(shí)函數(shù)會(huì)暫停并保存當(dāng)前所有的運(yùn)行信息,返回yield的值。并在下一次執(zhí)行 next()方法時(shí)從當(dāng)前位置繼續(xù)運(yùn)行。

那么如何創(chuàng)建一個(gè)生成器呢?

2、生成器的創(chuàng)建

最簡(jiǎn)單最簡(jiǎn)單的方法就是把一個(gè)列表生成式的 [] 改成 ()

# -*- coding: UTF-8 -*-
gen= (x * x for x in range(10))
print(gen)

輸出的結(jié)果:

<generator object <genexpr> at 0x0000000002734A40>

創(chuàng)建 List 和 generator 的區(qū)別僅在于最外層的 []() 。但是生成器并不真正創(chuàng)建數(shù)字列表, 而是返回一個(gè)生成器,這個(gè)生成器在每次計(jì)算出一個(gè)條目后,把這個(gè)條目“產(chǎn)生” ( yield ) 出來。 生成器表達(dá)式使用了“惰性計(jì)算” ( lazy evaluation,也有翻譯為“延遲求值”,我以為這種按需調(diào)用 call by need 的方式翻譯為惰性更好一些),只有在檢索時(shí)才被賦值( evaluated ),所以在列表比較長(zhǎng)的情況下使用內(nèi)存上更有效。

那么竟然知道了如何創(chuàng)建一個(gè)生成器,那么怎么查看里面的元素呢?

3、遍歷生成器的元素

按我們的思維,遍歷用 for 循環(huán),對(duì)了,我們可以試試:

# -*- coding: UTF-8 -*-
gen= (x * x for x in range(10))

for num  in  gen :
    print(num)

沒錯(cuò),直接這樣就可以遍歷出來了。當(dāng)然,上面也提到了迭代器,那么用 next() 可以遍歷嗎?當(dāng)然也是可以的。

4、以函數(shù)的形式實(shí)現(xiàn)生成器

上面也提到,創(chuàng)建生成器最簡(jiǎn)單最簡(jiǎn)單的方法就是把一個(gè)列表生成式的 [] 改成 ()。為啥突然來個(gè)以函數(shù)的形式來創(chuàng)建呢?

其實(shí)生成器也是一種迭代器,但是你只能對(duì)其迭代一次。這是因?yàn)樗鼈儾]有把所有的值存在內(nèi)存中,而是在運(yùn)行時(shí)生成值。你通過遍歷來使用它們,要么用一個(gè)“for”循環(huán),要么將它們傳遞給任意可以進(jìn)行迭代的函數(shù)和結(jié)構(gòu)。而且實(shí)際運(yùn)用中,大多數(shù)的生成器都是通過函數(shù)來實(shí)現(xiàn)的。那么我們?cè)撊绾瓮ㄟ^函數(shù)來創(chuàng)建呢?

先不急,來看下這個(gè)例子:

# -*- coding: UTF-8 -*-
def my_function():
    for i in range(10):
        print ( i )

my_function() 

輸出的結(jié)果:

0
1
2
3
4
5
6
7
8
9

如果我們需要把它變成生成器,我們只需要把 print ( i ) 改為 yield i 就可以了,具體看下修改后的例子:

# -*- coding: UTF-8 -*-
def my_function():
    for i in range(10):
        yield i

print(my_function()) 

輸出的結(jié)果:

<generator object my_function at 0x0000000002534A40>

但是,這個(gè)例子非常不適合使用生成器,發(fā)揮不出生成器的特點(diǎn),生成器的最好的應(yīng)用應(yīng)該是:你不想同一時(shí)間將所有計(jì)算出來的大量結(jié)果集分配到內(nèi)存當(dāng)中,特別是結(jié)果集里還包含循環(huán)。因?yàn)檫@樣會(huì)耗很大的資源。

比如下面是一個(gè)計(jì)算斐波那契數(shù)列的生成器:

# -*- coding: UTF-8 -*-
def fibon(n):
    a = b = 1
    for i in range(n):
        yield a
        a, b = b, a + b

# 引用函數(shù)
for x in fibon(1000000):
    print(x , end = ' ')

運(yùn)行的效果:

計(jì)算斐波那契數(shù)列的生成器

你看,運(yùn)行一個(gè)這么打的參數(shù),也不會(huì)說有卡死的狀態(tài),因?yàn)檫@種方式不會(huì)使用太大的資源。這里,最難理解的就是 generator 和函數(shù)的執(zhí)行流程不一樣。函數(shù)是順序執(zhí)行,遇到 return 語句或者最后一行函數(shù)語句就返回。而變成 generator 的函數(shù),在每次調(diào)用 next() 的時(shí)候執(zhí)行,遇到 yield語句返回,再次執(zhí)行時(shí)從上次返回的 yield 語句處繼續(xù)執(zhí)行。

比如這個(gè)例子:

# -*- coding: UTF-8 -*-
def odd():
    print ( 'step 1' )
    yield ( 1 )
    print ( 'step 2' )
    yield ( 3 )
    print ( 'step 3' )
    yield ( 5 )

o = odd()
print( next( o ) ) 
print( next( o ) ) 
print( next( o ) ) 

輸出的結(jié)果:

step 1
1
step 2
3
step 3
5

可以看到,odd 不是普通函數(shù),而是 generator,在執(zhí)行過程中,遇到 yield 就中斷,下次又繼續(xù)執(zhí)行。執(zhí)行 3 次 yield 后,已經(jīng)沒有 yield 可以執(zhí)行了,如果你繼續(xù)打印 print( next( o ) ) ,就會(huì)報(bào)錯(cuò)的。所以通常在 generator 函數(shù)中都要對(duì)錯(cuò)誤進(jìn)行捕獲。

5、打印楊輝三角

通過學(xué)習(xí)了生成器,我們可以直接利用生成器的知識(shí)點(diǎn)來打印楊輝三角:

# -*- coding: UTF-8 -*-
def triangles( n ):         # 楊輝三角形
    L = [1]
    while True:
        yield L
        L.append(0)
        L = [ L [ i -1 ] + L [ i ] for i in range (len(L))]

n= 0
for t in triangles( 10 ):   # 直接修改函數(shù)名即可運(yùn)行
    print(t)
    n = n + 1
    if n == 10:
        break

輸出的結(jié)果為:

[1]
[1, 1]
[1, 2, 1]
[1, 3, 3, 1]
[1, 4, 6, 4, 1]
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
[1, 7, 21, 35, 35, 21, 7, 1]
[1, 8, 28, 56, 70, 56, 28, 8, 1]
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]