<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] ## 列表生成式 通過列表生成式,我們可以直接創建一個列表 ``` >>> a = [i+1 for i in range(10)] >>> a [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ``` >通過列表生成式,我們可以直接創建一個列表。但是,列表容量肯定是有限的。如果創建一個包含100萬個元素的列表,不僅占用很大的存儲空間,假如我們僅僅需要訪問前面幾個元素,那后面絕大多數元素占用的空間都白白浪費了。 ## 生成器(generator) 通過生成器一邊循環一邊計算的機制,就不必創建完整的list,從而節省大量的空間,如果獨立函數調用,函數可以暫停或者掛起,并在需要時從暫停地方繼續或者重新開始,需要用`yield`實現 ### 列表生成器 要創建一個generator,有很多種方法。第一種方法很簡單,只要把一個列表生成式的`[]`改成`()`,就創建了一個generator: ``` >>> L = [x * x for x in range(10)] >>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> g = (x * x for x in range(10)) >>> g <generator object <genexpr> at 0x1022ef630> ``` 創建`L`和`g`的區別僅在于最外層的`[]`和`()`,`L`是一個list,而`g`是一個generator。 #### 獲取生成器的值(next函數) 生成器中的數據,可以通過`next()`函數獲得generator的下一個返回值: ``` >>> next(g) 0 ......略 >>> next(g) 81 >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration ``` >generator保存的是算法,每次調用`next(g)`就計算出`g`的下一個元素的值,直到計算到最后一個元素,沒有更多的元素時,拋出`StopIteration`的錯誤。 #### 獲取生成器的值(for循環) 不斷調用`next(g)`實在是太變態了,正確的方法是使用`for`循環,因為generator也是可迭代對象: ``` >>> g = (x * x for x in range(10)) >>> for n in g: ... print(n) ... 0 ......略 81 ``` >創建了一個generator后,基本上永遠不會調用next(),而是通過for循環來迭代它,并且不需要關心StopIteration的錯誤。 ### 函數生成器 generator非常強大。如果推算的算法比較復雜,用類似列表生成式的for循環無法實現的時候,還可以用函數來實現。 如果一個函數定義中包含`yield`關鍵字,那么這個函數就不再是一個普通函數,而是一個generator: #### 斐波拉契數列生成器 著名的斐波拉契數列(Fibonacci),除第一個和第二個數外,任意一個數都可由前兩個數相加得到: `1, 1, 2, 3, 5, 8, 13, 21, 34, ...` ``` def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return 'done' ``` 要把`fib`函數變成generator,只需要把`print(b)`改為`yield b`就可以了: ``` def fib(max): n,a,b = 0,0,1 while n < max: #print(b) yield b a,b = b,a+b n += 1 return 'done' ``` 驗證一下這個是不是編程函數生成器 ``` >>> f = fib(6) >>> f <generator object fib at 0x104feaaa0> ``` #### 函數生成器與函數的區別 最難理解的就是generator和函數的執行流程不一樣。函數是順序執行,遇到return語句或者最后一行函數語句就返回。而變成generator的函數,在每次調用next()的時候執行,遇到yield語句返回,再次被next()調用時從上次返回的yield語句處繼續執行。 ``` data = fib(10) print(data) print(data.__next__()) print(data.__next__()) print("干點別的事") print(data.__next__()) print(data.__next__()) #>:輸出 <generator object fib at 0x000002E33EEFFCA8> 1 1 干點別的事 2 3 ``` > `在上面fib`的例子,我們在循環過程中不斷調用`yield`,就會不斷中斷。當然要給循環設置一個條件來退出循環,不然就會產生一個無限數列出來。同樣的,把函數改成generator后,我們基本上從來不會用`next()`來獲取下一個返回值,而是直接使用`for`循環來迭代: ``` >>> for n in fib(6): ... print(n) ... 1 1 ......略 8 ``` ### 捕獲生成器錯誤(StopIteration) 用for循環調用generator時,發現拿不到generator的return語句的返回值。如果想要拿到返回值,必須捕獲StopIteration錯誤,返回值包含在StopIteration的value中: ``` >>> g = fib(6) >>> while True: ... try: ... x = next(g) ... print('g:', x) ... except StopIteration as e: ... print('Generator return value:', e.value) ... break ... g: 1 g: 1 ......略 g: 8 Generator return value: done ``` > 關于如何捕獲錯誤的詳細情況,看錯誤捕獲相關筆記。 ## 迭代器(Iterator) 迭代器就是可將可迭代對象(如列表、元組、字典等)循環輸出的一種工具,比如`for...in...`就是應用了迭代器的原理。 如果想轉成迭代器可以用`iter()`函數,然后用`next()`函數就可以一個個內容輸出了,或者也可以結合for輸出,每輸出一個,迭代器里就少一個,直到空了就不能輸出了 我們已經知道,可以直接作用于`for`循環的數據類型有以下兩類種: * 一類是集合數據類型,如`list`、`tuple`、`dict`、`set`、`str`等; * 一類是`generator`,包括生成器和帶`yield`的generator function。 ### 可迭代對象(Iterable) 這些可以直接作用于`for`循環的對象統稱為可迭代對象:`Iterable`。可以使用`isinstance()`判斷一個對象是否是`Iterable`對象: ``` >>> from collections import Iterable >>> isinstance([], Iterable) True >>> isinstance({}, Iterable) True >>> isinstance('abc', Iterable) True >>> isinstance((x for x in range(10)), Iterable) True >>> isinstance(100, Iterable) False` ``` ### 迭代器(Iterator) 而生成器不但可以作用于for循環,還可以被next()函數不斷調用并返回下一個值,直到最后拋出StopIteration錯誤表示無法繼續返回下一個值了。 **可以被next()函數調用并不斷返回下一個值的對象稱為迭代器:Iterator。** 可以使用isinstance()判斷一個對象是否是Iterator對象: ``` >>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance('abc', Iterator) False ``` 生成器都是`Iterator`對象,但`list`、`dict`、`str`雖然是`Iterable`,卻不是`Iterator`。 ### 可迭代對象轉為迭代器 把`list`、`dict`、`str`等`Iterable`變成`Iterator`可以使用`iter()`函數: ``` >>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True ``` >為什么`list`、`dict`、`str`等數據類型不是`Iterator`? >>這是因為Python的`Iterator`對象表示的是一個數據流,Iterator對象可以被`next()`函數調用并不斷返回下一個數據,直到沒有數據時拋出`StopIteration`錯誤。可以把這個數據流看做是一個有序序列,但我們卻不能提前知道序列的長度,只能不斷通過`next()`函數實現按需計算下一個數據,所以`Iterator`的計算是惰性的,只有在需要返回下一個數據時它才會計算。 `Iterator`甚至可以表示一個無限大的數據流,例如全體自然數。而使用list是永遠不可能存儲全體自然數的。 ## 迭代器概念總結 * 凡是可作用于`for`循環的對象都是`Iterable`類型; * 凡是可作用于`next()`函數的對象都是`Iterator`類型,它們表示一個惰性計算的序列; * 集合數據類型如`list`、`dict`、`str`等是`Iterable`但不是`Iterator`,不過可以通過`iter()`函數獲得一個`Iterator`對象。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看