迭代器,生成器,解析式

在python中容器,可迭代對象,迭代器,生成器,解析式這幾個概念容易混淆,它們的關係如下圖所示

 

容器(container)

容器是用來儲存多個數據的一種數據結構,python中的容器有

  1. list,deque,...
  2. set,frozeset,...
  3. dict,defalutdict,orderdict,counter,...
  4. tuple,namedtuple,...
  5. str

 

可迭代對象(Iterable )

可以直接作用於for循環的對象統稱爲可迭代對象,即實現了__iter__方法或__getitem__的對象,包括以下對象

  1. 大部分容器(container),如list、tuple、dict、set、str等
  2. 流式數據處理對象,如文件對象,管道對象等
  3. 生成器,包括生成器函數和生成器表達式。

 

迭代器(Iterator)

  1. 迭代器是實現了__next__()方法的對象。
  2. 迭代器被next()函數調用返回下一個值,直到沒有數據時拋出StopIteration錯誤。

可迭代對象和迭代器關係

  1. Iterable可以通過iter()函數轉換得到 Iterator,
  2. Iterator可以直接作用於for循環,所以Iterator是Iterable。Iterator是繼承Iterable的。
  3. 可迭代對象的大小是確定的,但迭代器的迭代次數是不確定的,每調用一次next()就往下走一步,它是惰性的。

實例

isinstance() 是python內建函數,返回對象是否是類或其子類的實例。
print(isinstance([], collections.Iterable))  # True
print(isinstance([], collections.Iterator))  # False
print(isinstance(iter([]), collections.Iterator))  # True
print(isinstance(iter([]), collections.Iterable))  # True
# 生成器是一種特殊的迭代器,Generator類繼承了Iterator
print(isinstance((x * x for x in range(10)), collections.Iterable))  # True
# 創建可迭代對象的三種方式
class FibIterator():
    def __init__(self, f):
        self.f = f
    def __iter__(self):
        return self
    def __next__(self):
        if self.f.num > 10:
            raise StopIteration()
        self.f.num += 1
        self.f.a, self.f.b = self.f.b, self.f.a + self.f.b
        return self.f.a
class FibIterable():
    def __init__(self):
        self.a = 0
        self.b = 1
        self.num = 0
    def __iter__(self):
        return FibIterator(self)
class FibIterable2():
    def __init__(self):
        self.a = 0
        self.b = 1
        self.num = 0
    def __iter__(self):
        while self.num <= 10:
            self.num += 1
            self.a, self.b = self.b, self.a + self.b
            yield self.a
class FibIterable3():
    def __init__(self):
        self.a = 0
        self.b = 1
        self.num = 0
    def __getitem__(self, item):
        if item > 10:
            raise StopIteration()
        self.a, self.b = self.b, self.a + self.b
        return self.a
f = FibIterable()
for i in f:
    print(i, end=' ')
print()  # 1 1 2 3 5 8 13 21 34 55 89 
f2 = FibIterable2()
for i in f2:
    print(i, end=' ')
print()  # 1 1 2 3 5 8 13 21 34 55 89 
f3 = FibIterable3()
for i in f3:
    print(i, end=' ')
print()  # 1 1 2 3 5 8 13 21 34 55 89

 

生成器(generator )

  1. 生成器其實就是一種特殊的迭代器。它是一種更爲高級、更爲優雅的迭代器。
  2. 生成器有兩種類型:生成器函數以及生成器表達式。生成器函數就是包含yield參數的函數。生成器表達式與列表解析式類似。
  3. 形如 (elem for elem in [1, 2, 3]) 的表達式,稱爲生成器表達式。所以只要把列表解析式的[]改成()就變成了生成器
  4. 生成器使用了惰性計算,即在使用的時候才產生結果。所以在數據較多的情況下減少內存佔用
  5. Gennerator類繼承了Iterator。

生成器的兩種使用形式實例

gen = (i for i in range(2))
print(gen)  # <generator object <genexpr> at 0x000000000216FDB0>
def f(n):
    for i in range(n):
        yield i
print(f(2))  # <generator object f at 0x000000000216FEB8>
for i in gen:
    print(i, end='')  # 01
for i in f(2):
    print(i, end='')  # 01
利用生成器實現斐波那契數列
def fib(n):
    a = 0
    b = 1
    for i in range(n):
        a, b = b, a + b
        yield a
for i in fib(10):
    print(i, end=' ')

輸出

1 1 2 3 5 8 13 21 34 55 

 

解析式

  1. 解析式包括列表解析式,集合解析式,字典解析式
  2. 解析式能用一行代碼代替十幾行代碼,而且不損失任何可讀性。而且,效率還要高很多

列表解析基本語法

[expression for iter_val in iterable]

[expression for iter_val in iterable if cond_expr]

集合解析基本語法

{expression for iter_val in iterable]}

字典解析基本語法

{expression1: expression2 for iter_val in iterable}

實例

print([i ** 2 for i in range(1, 11)])  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
print([i ** 2 for i in range(1, 11) if i < 5])  # [1, 4, 9, 16]
print([(a, b) for a in range(1, 3) for b in ['x', 'y']])  # [(1, 'x'), (1, 'y'), (2, 'x'), (2, 'y')]
print('\n'.join([' '.join(['%d*%d=%d' % (x, i, x * i) for i in range(1, x + 1)]) for x in range(1, 10)]))
# 1*1=1
# 2*1=2 2*2=4
# 3*1=3 3*2=6 3*3=9
# 4*1=4 4*2=8 4*3=12 4*4=16
# 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
# 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
# 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
# 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
# 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
print({x * x for x in range(1, 11)})  # {64, 1, 4, 36, 100, 9, 16, 49, 81, 25}
print({x: x * x for x in range(1, 11)})  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81, 10: 100}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章