Python面試題之Python生成器

2022-05-10 01:05:14 字數 4653 閱讀 2558

首先說明一下生成器也是迭代器,也有迭代器的那些優點。

那為什麼要生成器呢?因為到目前為止都 不是你寫的迭代器,都是別人定義好的。那如何自己去造乙個迭代器呢?下面的內容就會給你答案。

想要自己造乙個迭代器,我們可以根據迭代器的特徵(只要乙個物件有__iter____next__方法那它就是迭代器),自己定義乙個類,然後定義乙個__iter__()__next__(), 然後這個類例項化的物件就是乙個迭代器啦。

但是這樣寫太麻煩啦!何況我們現在還沒有學到類的知識,怎麼辦?給你乙個魔法棒,讓你快速優雅高效地造乙個迭代器。

第一種自造迭代器的方法就是使用yield關鍵字。具體怎麼實現呢?

非常簡單,如下所示:

def

g():

print("

hey~ 生成器")

yield 1

上面的寫法非常類似於函式的定義,相當於把return換成了yield(當然,並沒有這麼簡單)。

此時,我執行g()返回的就是乙個生成器。就是這麼簡單。

ret =g()

print(ret) #

輸出

但是這裡有個特別需要注意的地方,也是與函式最明顯的區別:

我們執行g()的時候,並沒有列印"hey~ 生成器",就像函式沒執行一樣。

這也是生成器乙個非常重要的特點,那就是你執行g()返回的是乙個生成器,同時只有在迭代它(呼叫它的__next__())的時候它才開始執行內部**,碰到yield關鍵字就返回yield後面的值並停止。

print(ret.__next__())  $print(next(ret))
輸出:

hey~生成器

1

當然for迴圈它也是可以的:

for i in

ret:

print(i)

輸出:

hey~生成器

1

yield還可以多次執行,這與return也有區別。

def

g2():

print("

hey~ 生成器1")

yield 1

print("

hey~ 生成器2")

yield 2ret = g2()

此時,你執行下next(ret),會列印"嘿!生成器1",然後返回乙個1,再執行一次next(ret),會列印出"嘿!生成器2",然後返回乙個2

print

(next(ret))#輸出

hey~生成器1

1print

(next(ret))#輸出

hey~生成器2

2

在乙個函式裡return只能執行一次,return之後函式就徹底結束了:

def

test_return():

return 1

return 2 #

永不執行

return 3 #

永不執行

yield之後可以儲存函式的執行狀態,下次繼續執行:

def

test_yield():

yield 1

yield 2 #

下次next()後執行

yeild 3 #

下次next()後執行

下面的例子中,使用return時,只能返回0

def

test_return2():

for i in range(10):

return i #

只能返回0,函式就結束了

使用yield能夠依次返回0~9

def

test_yield2():

for i in range(10):

yield i #

每呼叫一次next()就會一次彈出0~9

yield把函式變成了生成器(生成器就是迭代器)。

為函式封裝好了__iter____next__方法,把函式的執行結果做成了迭代器。

遵循迭代器的取值方式 —obj.__next__(),觸發的是函式的執行。函式暫停與繼續執行的狀態都是由yield儲存的。

倒計時的例子:

def

countdown(n):

print("

倒計時開始")

while n >0:

yield

n n -= 1

print("

發射")

分析下面語句的執行過程:

g = countdown(5)

print(g.__next__()) #

列印"倒計時開始" 返回5 (此時n=5)

print(g.__next__()) #

返回4 (此時n=4)

print(g.__next__()) #

返回3 (此時n=3)

print(g.__next__()) #

返回2 (此時n=2)

print(g.__next__()) #

返回1 (此時n=1)

print(g.__next__()) #

列印"發射" 丟擲stopiteration異常(此時n=0)

呼叫__next__()時函式執行內部**,到yield關鍵字時暫停:

g = countdown(5)

print(g.__next__())

輸出:

倒計時開始

5

生成器也是不能後退:

g = countdown(5)

print(g.__next__

())print(g.__next__

())for i in

g:

print(i)

輸出:

倒計時開始54

-- for --32

1發射

每呼叫一次countdown(5)得到的都是不同的生成器

for i in countdown(5):

print

(i)

for i in copuntdown(5):

print(i)

輸出:

5

5

下面的例子也是一樣,每一次print中countdown(5)都是乙個全新的生成器,所以列印出來的值都是5

print(countdown(5).__next

())print(countdown(5).__next

())print(countdown(5).__next())

輸出:

5

55

我們之前學過列表推導式,是這樣寫的:

>>> [i for i in range(10)]

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

這樣來得到乙個元素數量較小的列表是非常方便的,但是如果要建立乙個元素數量巨大的列表,就不那麼友好了

>>> [i for i in range(10000000000)]

...

這個時候只要把換成()就把列表推導式 變成了生成器表示式,得到的就是乙個生成器物件,就是這麼神奇。

這就是第二種自造迭代器的方法。

>>> (i for i in range(10))

at 0x101fef6d0>

我們可以直接使用for迴圈遍歷上面得到的生成器:

>>> for i in  (i for i in range(10)):

...

print

(i)... 01

2345

6789

這樣我們就能自信的建立個10000000000元素的生成器,不擔心記憶體會爆了。

>>> (i for i in range(10000000000))

at 0x101fef728>

最後的總結:

python語法面試題 python面試題

1.去重,集合 集合的乙個重要特點是 自動去除重複的值 li 1,2,3,1,1,2,2,3,3 去除重複的元素 set set li 轉換為集合,因為集合會自動去重。print set li list set 將集合轉換為列表print li 2.生成器 規則 生成器函式,或者生成器表示式,在呼叫...

C 面試題之i 面試題

i 面試題1.cpp 中國台灣某著名防毒軟體公司2005年10月面試題 int i 3,j 4 i?i j printf d d n i,j a.3 3 b.4 4 c.3 4 d.4 3 答案b i 面試題2.cpp 中國某著名計算機金融軟公司2005年面試題 int x 1,j 2 int k ...

C 面試題之sizeof面試題

sizeof面試題1.cpp what is the output of the following code?美國某著名計算機軟硬體公司面試題 include include include using namespace std structa structb int main 解析 ss1是乙...