推导式可方便生成数据集合,而生成器可返回一个可迭代的对象。
推导式
推导式表达式是一种可从一个序列构建另外一个新数据序列的数据处理方式,Python中有三种推导式:列表推导式、字典推导式和集合推导式。
列表推导式
列表推导式用于快速生成一个列表:
[表达式 for 变量 in 可迭代对象]
[表达式 for 变量 in 可迭代对象 if 条件]
如生成100内偶数列表:
numbers = [i for i in range(100) if i%2==0]
字典推导式
字典推导式用于快速生成一个字典:
{键:值表达式 for 变量 in 可迭代对象}
{键:值表达式 for 变量 in 可迭代对象 if 条件}
如快速对换字典的键与值:
numMap = {1:'one', 2:'two', 3:'three'}
numRev = {v:k for k,v in numMap.items()}
集合推导式
集合推导式与列表推导式类似,只是外面使用大括号:
{表达式 for 变量 in 可迭代对象}
{表达式 for 变量 in 可迭代对象 if 条件}
如获取字符串中字符数:
s = 'abcdeffsdfsaf'
ch = {x for x in s}
print(len(ch))
生成器
一边循环一边计算的机制,称为生成器(generator):
- 生成器能迭代的关键是其有
__next__
方法:- 通过next(g),获取下一个元素;当没有更多元素时,会抛出
StopIteration
异常; - 通过
for x in g
循环来依次获取生成器中元素;
- 通过next(g),获取下一个元素;当没有更多元素时,会抛出
- 带有yield的函数不再是普通函数,而是一个生成器:
- yield类似return返回一个值,但会记住此位置,下次迭代时从下一条语句继续执行;
.send()
与next()
类似,但会传递一个值,此值作为yield表达式整体结果返回。
生成器表达式
生成器与推导式类似,但生成器表达式占更少的内存,因为:
- 生成器表达式中的元素是按需逐个生成的;
- 推导式是一次将所有元素生成,放到内存中。
(表达式 for 变量 in 可迭代对象)
(表达式 for 变量 in 可迭代对象 if 条件)
也可把生成器转换为其他集合(tuple或list)来获取其全部元素:
gen = (x**2 for x in range(5))
print(tuple(gen))
函数生成器
通过yield可把普通函数变成生成器:
def genNum(count=10):
for n in range(count):
yield n
num = genNum(5)
for i in num:
print(i)
send
要使send生效(send的参数为yield的返回值),需要修改yield语句:
- 获取返回值,然后重设yield的变量;
- 在调用send前,需要要已调用过next(保证已挂在yield语句处);
def genNum(count=10):
i = 0
while i < count:
v = (yield i)
if v:
i = v
else:
i += 1
num = genNum()
print(next(num)) # 0
print(num.send(3)) # 跳过1、2,返回3
for i in num: # 从4开始
print(i)
可迭代对象
能够逐一迭代返回元素的对象即为可迭代对象,包括:
- 所有序列类型:str、list、tuple、range;
- 非序列集合:set、dict、文件对象(open返回的);
- 实现了
__iter__()
方法的任意对象; - 实现了
__getitem__()
方法的任意对象;
迭代器
定义了__iter__()
(必须返回一个迭代器)方法的对象,就实现了迭代协议;即为一个迭代器:
- 所有可迭代对象,都可通过
iter()
方法转换为迭代器:如iter('abcd')
; - 迭代器使用
next()
进行迭代操作;*
class GenNumbers:
def __init__(self, count):
self.count = count
def __iter__(self):
self.n = 1
return self
def __next__(self):
if self.n <= self.count:
x = self.n
self.n += 1
return x
else:
raise StopIteration
gen = GenNumbers(10)
for i in gen:
print(i)