在python中容器,可迭代对象,迭代器,生成器,解析式这几个概念容易混淆,它们的关系如下图所示
容器(container)
容器是用来储存多个数据的一种数据结构,python中的容器有
- list,deque,...
- set,frozeset,...
- dict,defalutdict,orderdict,counter,...
- tuple,namedtuple,...
- str
可迭代对象(Iterable )
可以直接作用于for循环的对象统称为可迭代对象,即实现了__iter__方法或__getitem__的对象,包括以下对象
- 大部分容器(container),如list、tuple、dict、set、str等
- 流式数据处理对象,如文件对象,管道对象等
- 生成器,包括生成器函数和生成器表达式。
迭代器(Iterator)
- 迭代器是实现了__next__()方法的对象。
- 迭代器被next()函数调用返回下一个值,直到没有数据时抛出StopIteration错误。
可迭代对象和迭代器关系
- Iterable可以通过iter()函数转换得到 Iterator,
- Iterator可以直接作用于for循环,所以Iterator是Iterable。Iterator是继承Iterable的。
- 可迭代对象的大小是确定的,但迭代器的迭代次数是不确定的,每调用一次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 )
- 生成器其实就是一种特殊的迭代器。它是一种更为高级、更为优雅的迭代器。
- 生成器有两种类型:生成器函数以及生成器表达式。生成器函数就是包含yield参数的函数。生成器表达式与列表解析式类似。
- 形如 (elem for elem in [1, 2, 3]) 的表达式,称为生成器表达式。所以只要把列表解析式的[]改成()就变成了生成器
- 生成器使用了惰性计算,即在使用的时候才产生结果。所以在数据较多的情况下减少内存占用
- 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
解析式
- 解析式包括列表解析式,集合解析式,字典解析式
- 解析式能用一行代码代替十几行代码,而且不损失任何可读性。而且,效率还要高很多
列表解析基本语法
[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}