python基礎(chǔ)學(xué)習(xí)筆記(十一)
2013-05-14 23:31 ?蟲師 閱讀( ... ) 評論( ... ) 編輯 收藏?
?
迭代器
?
本節(jié)進(jìn)行迭代器的討論。只討論一個(gè)特殊方法 ----?__iter__?? ,這個(gè)方法是迭代器規(guī)則的基礎(chǔ)。
?
迭代器規(guī)則
迭代的意思是重復(fù)做一些事很多次 --- 就像在循環(huán)中做的那樣。 __iter__? 方法返回一個(gè)迭代器,所謂迭代器就是具有 next 方法的對象,在調(diào)用 next 方法時(shí),迭代器會(huì)返回它的下一個(gè)值。如果 next 方法被調(diào)用,但迭代器沒有值可以返回,就會(huì)引發(fā)一個(gè) StopIteration 異常。
?
這里是一個(gè)婓波那契數(shù)例,使用迭代器如下:
class
Fibs:
def
__init__
(self):
self.a
=
0
self.b
= 1
def
next(self):
self.a , self.b
= self.b , self.a +
self.b
return
self.a
def
__iter__
(self):
return
self
>>> fibs =
Fibs()
>>>
for
f
in
fibs:
if
f > 1000
:
print
f
break
#
因?yàn)樵O(shè)置了break ,所以循環(huán)在這里停止。
1597
內(nèi)建函數(shù) iter 可以從可迭代的對象中獲得迭代器。
>>> it = iter([1,2,3
])
>>>
it.next()
1
>>>
it.next()
2
?
從迭代器得到序列
除了在迭代器和可迭代對象上進(jìn)行迭代外,還能把它們轉(zhuǎn)換為序列。在大部分能使用序列的情況下,能使用迭代器替換。
class
TestIterator:
value
=
0
def
next(self):
self.value
+= 1
if
self.value > 10:
raise
StopIteration
return
self.value
def
__iter__
(self):
return
self
>>> ti =
TestIterator()
>>>
list(ti)
[
1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
?
生成器
?
生成器也叫?簡單生成器,生成器可以幫助讀者寫出非常優(yōu)雅的代碼,當(dāng)然,編寫任何程序時(shí)不使用生成器也是可以的。
?
創(chuàng)建生成器
創(chuàng)建一個(gè)生成器就像創(chuàng)建函數(shù)一樣簡單。
>>>
def
flatten(nested):
for
sublist
in
nested:
for
element
in
sublist:
yield
element
>>> nested = [[1,2],[3,4],[5
]]
#
使用for循環(huán)
>>>
for
num
in
flatten(nested):
print
num
1
2
3
4
5
#
或使用list函數(shù)
>>>
list(flatten(nested))
[
1, 2, 3, 4, 5]
?
遞歸生成器
上面創(chuàng)建的生成器只能處理兩層嵌套,為了處理嵌套使用了兩個(gè) for 循環(huán),如果要處理任意層的嵌套呢?例如,可以每層嵌套需要增加一個(gè) for 循環(huán),但不知道有幾層嵌套,所以必須把解決方案變得更靈活,現(xiàn)在可以用遞歸來解決。
>>>
def
fla(aa):
try
:
for
bb
in
aa:
for
cc
in
fla(bb):
yield
cc
except
TypeError:
yield
aa
>>> list(fla([[[1],2],3,4,[5,[6,7]],8]))
#
注意括號層次比較多
[1, 2, 3, 4, 5, 6, 7, 8]
當(dāng) fla 被調(diào)用時(shí)有兩種情況: 基本情況和需要遞歸的情況
在基本的情況中,函數(shù)被告知展開一個(gè)元素,這種情部下, for 循環(huán)會(huì)引發(fā)一個(gè) TypeError? 異常,生成會(huì)產(chǎn)生一個(gè)元素。
如果展開的是一個(gè)列表,那么就需要特殊情況處理。程序必須遍歷所有的子列表,并對它們調(diào)用 fla 。
-------------------
上面的做法有一個(gè)問題:如果 aa? 是一個(gè)類似于字符串的對象(字符串、 Unicode 、 UserString 等),那么它就是一個(gè)序列,不會(huì)引發(fā) TypeError ,但是你不想對這樣的對象進(jìn)行迭代。
為了處理這種情況,則必須在生成器的開始處添加一個(gè)檢查語句。試著將傳入的對象和一個(gè)字符串拼接,看看會(huì)不會(huì)出現(xiàn) TypeError ,這是檢查一個(gè)對象是不是類似于字符串最簡單快速的方法。
>>>
def
flatten(nested):
try
:
#
不要迭代類似字符串的對象
try
:nested +
''
except
TypeError:
pass
else
:
raise
TypeError
for
sublist
in
nested:
for
element
in
flatten(sublist):
yield
element
except
TypeError:
yield
nested
>>> list(flatten([
'
foo
'
,[
'
bar
'
,[
'
baz
'
]]]))
[
'
foo
'
,
'
bar
'
,
'
baz
'
]
如果 nested+ ’’ ?引發(fā)了一個(gè) TypError? ,它就會(huì)被忽略。如果沒有引發(fā) TypeError ,那么內(nèi)層 try 語句就會(huì)引發(fā)一個(gè)它自己的 TypeError 異常。
?
?
生成器方法
生成器新屬性是在開始運(yùn)行后為生成器提供值的能力。表現(xiàn)為生成器和“外部世界”進(jìn)行交流的渠道:
*? 外部作用域訪問生成器的 send 方法,就像訪問 next? 方法一樣,只不過前者使用一個(gè)參數(shù)(發(fā)送的“消息” --- 任意對象)
*? 在內(nèi)部則掛起生成器, yield 現(xiàn)在作為表達(dá)式而不是語句使用,換句話說,當(dāng)生成器重新運(yùn)行的時(shí)候, yield 方法返回一個(gè)值,也就是外部通過 send 方法發(fā)送的值。如果 next? 方法被使用,那么 yield 方法返回 None.?
下面簡單的方例子來說明這種機(jī)制:
>>>
def
repeater(value):
while
True:
new
=(
yield
value)
if
new
is
not
None:value =
new
>>> r = repeater(42
)
>>>
r.next()
42
>>> r.send(
"
hello, world!
"
)
'
hello, world!
'
生成器的另兩個(gè)方法:
*?throw 方法(使用異常類型調(diào)用,還有可選的值以及回溯對象)用于在生成器內(nèi)引發(fā)一個(gè)異常(在 yield 表達(dá)式中)
*?close? 方法(調(diào)用時(shí)不用參數(shù))用于停止生成器。
?
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

