【Python學習筆記】列表生成式和生成器

一、列表生成式
      列表生成式是Python內置的能夠用來建立list的生成式python

      列表生成式, 它的基礎語法是: [exp for iter_var in iterable] 
      首先迭代 iterable 裏全部內容, 每一次迭代, 都把 iterable 裏相應內容放到 iter_var 中, 再在表達式 exp 中應用該 iter_var 的內容, 最後用表達式的計算值生成一個新的列表.算法

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import math# 導入數學公式模塊
from collections import Iterable# 判斷是否爲可迭代對象
import os# 導入os模塊


# 生成L1[0,1,2,3....,9]可使用range(0,10)
L1 = range(0,10)
print L1

# 生成L2[0*0,1*1,2*2,,,,,9*9]可使用range(0,10)和循環
L2 = []
for n in range(0,10):
    L2.append(n*n)
print L2

# 利用列表生成式能夠更方便的實現上面兩個例子
L1 = [m for m in range(0,10)]
print L1
L2 = [n*n for n in range(0,10)]
print L2

# 除此以外,還可使用兩層,三層等多層循環,但通常只用到兩層
L_Sum = [(x + y) for x in range(0,10) for y in range(10,20)]# 全排列,共有100種結果
print L_Sum
L_Cat = [(x,y) for x in '012' for y in "abc"]
print L_Cat

# 能夠在列表生成式的循環以後加上if,實現篩選功能,篩選的結果是一個新的list
L_Sel = [i for i in range(1,21) if i % 2 == 0]
print L_Sel

# 列表生成式中的for循環能夠同時使用兩個變量甚至多個變量
# 將dict變成對應的list,將key和values鏈接起來
D = {0:'a',1:'b',2:'c'}
L_L = [str(k) + '-' + v for k,v in D.iteritems()]
print L_L

# 將list中的全部字符串元素的大寫變成小寫
# 當list中包含字符串與整數時,使用lower()函數會報錯,因此,可使用內置函數先判斷一個元素是不是字符串
L = ['Abcd','aBcd',1,'abCd','abcD']
L_low = [s.lower() for s in L if (isinstance(s,str))]
print L_low
# 將list中的全部字符串元素的大寫變成小寫,其餘元素不變
L_l = [s.lower() if (isinstance(s,str)) else s for s in L  ]
print L_l

# 運用列表生成式能夠列出某目錄下額全部文件名和目錄名
L_file1 = [f for f in os.listdir('.')]# 當前目錄
print L_file1
L_file2 = [f for f in os.listdir(r'd:\\python')]# 指定目錄
print L_file2
# os.listdir('.')不能訪問其子文件夾
# 能夠經過os.path.walk遞歸遍歷,能夠訪問子文件夾,可是未進行格式化
L_file3 = [f for f in os.walk(r'd:\\python\\workspace')]# 當前目錄
print L_file3,'\n'
# 自定義格式化函數
def processDirectory ( args, dirname, filenames ):
    print 'Directory:',dirname
    for filename in filenames:
        print 'File\\\\:',filename
os.path.walk(r'd:\\python\\workspace', processDirectory, None )

運行結果:app

二、生成器函數

# ★★★先搞清與列表生成式的區別及生成器的原理★★★
經過列表生成式,咱們能夠直接建立一個列,當表達式的結果數量較少的時候, 使用列表生成式還好, 一旦數量級過大, 那麼將佔用很大的內存,若是僅僅訪問前面一部分的元素,則後面的絕大部分佔用的空間就浪費了。
而生成器並非當即把結果寫入內存,generator自己保存的一種計算方式(算法),經過不斷的獲取到相應的位置的值,是一邊循環一邊計算的機制,因此佔用的內存僅僅是對計算對象的保存,即解決使用列表生成式建立包含超級多的元素時形成的內存空間浪費的問題。
在Python中,能夠簡單地把列表生成式改爲generator,也能夠經過函數實現複雜邏輯的generator。
generator的工做原理:在for 循環的過程當中不斷計算出下一個元素,並在適當的條件結束for 循環。對於函數改爲的generator來講,遇到return語句或者執行到函數體最後一行語句,就是結束generator的指令, for 循環隨之結束。spa

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import math# 導入數學公式模塊
from collections import Iterable# 判斷是否爲可迭代對象
import os# 導入os模塊


# ★★使用生成器建立list列表時,與列表生成式很類似,即把中括號改成圓括號:即[]->()
L = [l ** 3 for l in range(0,10)]# 中括號[]
print L
G = (g ** 3 for g in range(0,10))# 小括號()
print G
# 從返回結果能夠看出,列表生成式直接返回的是結果值,生成器返回的是一個包含了對錶達式結果的計算引用的對象
# 區別:一、list生成式生成的list能夠直接打印,generator生成器沒法直接打印。二、list生成式使用的是[],generator生成器使用的是()

# ★能夠經過調用generator的next()方法打印各元素
G = (g ** 3 for g in range(0,10))
for i in range(0,10):#for i in range(0,11):
    print G.next()
# generator保存的是算法,每次調用next() ,就計算出下一個元素的值,直到計算到最後一個元素.
# 若是此時再使用next(),拋出StopIteration的錯誤。並且此時generator對象覺得空

# ★generator也是可迭代對象,因此基本上不會調用其next()方法,而是經過for 循環來迭代它
G = (g ** 3 for g in range(0,10))
if isinstance(G,Iterable):
    for i in G:
        print i

# 在Python中,能夠簡單地把列表生成式改爲generator,也能夠經過函數實現複雜邏輯的generator
# ★★若是一個函數定義中包含yield 關鍵字,那麼這個函數就再也不是一個普通函數,而是一個generator
# 若是推算的算法比較複雜,用相似列表生成式的for 循環沒法實現的時候,還能夠用函數來實現
# 例:斐波拉契數列(Fibonacci),除第一個和第二個數外,任意一個數均可由前兩個數相加獲得
def fib(N):# 打印前N個元素
    n, a, b = 0, 0, 1
    while n < N:
        print b
        a, b = b, a + b# ★對應連續賦值
        n = n + 1
fib(10)
# fib()函數其實是定義了斐波拉契數列的推算規則,這種邏輯其實很是相似generator
# ★要把fib()函數變成generator,只須要把print b 改成yield b
def fib(N):# 打印前N個元素
    n, a, b = 0, 0, 1
    while n < N:
        yield b
        a, b = b, a + b# ★對應連續賦值
        n = n + 1
f = fib(10)
print f.next()
print f.next()
print f.next()
print f.next()
# ★generator和函數的執行流程不同。函數是順序執行,遇到return語句或者最後一行函數語句就返回。
# 而變成generator的函數,在每次調用next() 的時候執行,遇到yield 語句返回,再次執行時從上次返回的yield 語句處繼續執行。

# ★把函數改爲generator後,基本上不會用到其next()方法來調用它,而是直接使用for 循環來迭代
for n in fib(10):
    print n

運行結果:code

                  

生成器是這樣一個函數,它記住上一次返回時在函數體中的位置。對生成器函數的第二次(或第 n 次)調用跳轉至該函數中間,而上次調用的全部局部變量都保持不變,便是說,在整個全部函數調用的參數都是第一次所調用時保留的,而不是新建立的對象

相關文章
相關標籤/搜索