1. 程式人生 > >python基礎教程(十一)

python基礎教程(十一)

list repeat stop row lis flatten ror 教程 [1]

叠代器

本節進行叠代器的討論。只討論一個特殊方法---- __iter__ ,這個方法是叠代器規則的基礎。

叠代器規則

叠代的意思是重復做一些事很多次---就像在循環中做的那樣。__iter__ 方法返回一個叠代器,所謂叠代器就是具有next方法的對象,在調用next方法時,叠代器會返回它的下一個值。如果next方法被調用,但叠代器沒有值可以返回,就會引發一個StopIteration異常。

這裏是一個婓波那契數例,使用叠代器如下:

技術分享
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    #因為設置了break ,所以循環在這裏停止。

1597
技術分享

內建函數iter可以從可叠代的對象中獲得叠代器。

>>> it = iter([1,2,3])
>>> it.next()
1
>>> it.next()
2

從叠代器得到序列

除了在叠代器和可叠代對象上進行叠代外,還能把它們轉換為序列。在大部分能使用序列的情況下,能使用叠代器替換。

技術分享
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]
技術分享

 

 

生成器

生成器也叫 簡單生成器,生成器可以幫助讀者寫出非常優雅的代碼,當然,編寫任何程序時不使用生成器也是可以的。

創建生成器

創建一個生成器就像創建函數一樣簡單。

技術分享
>>> def flatten(nested):
    for sublist in nested:
        for element in sublist:
            yield element

            
>>> nested = [[1,2],[3,4],[5]]
#使用for循環
>>> for num in flatten(nested):
    print num

    
1
2
3
4
5
#或使用list函數
>>> list(flatten(nested))
[1, 2, 3, 4, 5]
技術分享

遞歸生成器

上面創建的生成器只能處理兩層嵌套,為了處理嵌套使用了兩個for循環,如果要處理任意層的嵌套呢?例如,可以每層嵌套需要增加一個for循環,但不知道有幾層嵌套,所以必須把解決方案變得更靈活,現在可以用遞歸來解決。

技術分享
>>> 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]
技術分享

  

fla被調用時有兩種情況:基本情況和需要遞歸的情況

  在基本的情況中,函數被告知展開一個元素,這種情部下,for循環會引發一個TypeError 異常,生成會產生一個元素。

  如果展開的是一個列表,那麽就需要特殊情況處理。程序必須遍歷所有的子列表,並對它們調用fla

-------------------

上面的做法有一個問題:如果aa 是一個類似於字符串的對象(字符串、UnicodeUserString等),那麽它就是一個序列,不會引發TypeError,但是你不想對這樣的對象進行叠代。

為了處理這種情況,則必須在生成器的開始處添加一個檢查語句。試著將傳入的對象和一個字符串拼接,看看會不會出現TypeError,這是檢查一個對象是不是類似於字符串最簡單快速的方法。

技術分享
>>> 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+’’ 引發了一個TypError ,它就會被忽略。如果沒有引發TypeError,那麽內層try語句就會引發一個它自己的TypeError異常。

生成器方法

生成器新屬性是在開始運行後為生成器提供值的能力。表現為生成器和“外部世界”進行交流的渠道:

  * 外部作用域訪問生成器的send方法,就像訪問next 方法一樣,只不過前者使用一個參數(發送的“消息”---任意對象)

  * 在內部則掛起生成器,yield現在作為表達式而不是語句使用,換句話說,當生成器重新運行的時候,yield方法返回一個值,也就是外部通過send方法發送的值。如果next 方法被使用,那麽yield方法返回None.

下面簡單的方例子來說明這種機制:

技術分享
>>> 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!
技術分享

生成器的另兩個方法:

  * throw方法(使用異常類型調用,還有可選的值以及回溯對象)用於在生成器內引發一個異常(在yield表達式中)

  * close 方法(調用時不用參數)用於停止生成器。

python基礎教程(十一)