一.推导式
1.推导式介绍
python中有一种特有的语法,就是推导式(又称为解析式)。推导式是可以从一个数据序列构建另一个新的数据序列的结构体。共有三种推导:列表推导式,字典推导式,集合推导式。
2.列表推导式
基本语法:[out_express for out_express in input_list]
例如:生成一个[0,1,4,9,16]的列表。使用列表推导式代码如下:
odd_list = [i*i for i in range(5)]
print(odd_list)
我们可以发现,列表推导式非常便利,如果是使用循环或许是需要几行代码才看可以实现,但是现在用一行代码就可以实现了。
并且当列表推导式还需要满足某条件下才可以输出表达式时,可以通过以下语法规范实现:
[out_express for out_express in input_list if out_express_condition]
例如:li = [6,2,6,7,-15,8,-17,-10,-15,-4],将列表中小于0的元素平方并保存到新列表中。
li = [6,2,6,7,-15,8,-17,-10,-15,-4]
new_li = [i**2 for i in li if i < 0]
print(new_li)
嵌套循环推导式:[i for row in matrix for i in row]
例子:生成列表 li 为 ['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c'] 代码如下:
li = [ i + j for i in '123' for j in 'abc']
2.字典推导式
基本语法:{out_exp_key: out_exp_value for out_exp in input_list}
例子:字典的key值为列表li的元素索引,字典的value值为列表的元素,li = ["age","name","gender"]
代码如下:
li = ["age","name","gender"]
dic = {li.index(i):i for i in li}
print(dic)
并且字典推导式可以快速将字典中的 k , v互换。代码如下:
dic1 = {0:"0",1:"1",2:"2"}
dic2 = {v:k for k,v in dic1.items()}
print(dic2)
3.集合推导式
基本语法:{out_exp_res for out_exp in input_set}
例子:随机生成10个 1 - 100之间的元素,并且去重
代码如下:
s1 = {random.randint(1,100) for i in range(10)}
print(s1)
print(len(s1))
最后需要注意的是python没有元组推导式,python的元组推导式叫做生成器,它与推导式又是另外一个区别。
二.迭代器
1.python迭代器
迭代器是指的是迭代取值的工具,迭代是指一个重复的过程,每一次重复都是基于上一次结果而来的,迭代提供了一种通用的不依赖索引的迭代取值方式。
2.可迭代的对象
(1)可以用 for 循环遍历的对象都是可迭代的对象。
(2)str , list , tuple , dict ,set 等都是可迭代的对象。
(3)generator ,包括生成器和带 yield 的生成器函数。
3.判断是否可迭代
除了看内置是否有 __iter__ 方法来判断该对象是否是一个可迭代的对象之外,我么还可以使用 isinstance() 判断一个对象是否是 Iterable 对象。其中该函数用来判断是否是相应类型,与type()类似。
from collections import Iterable,Iterator
print(isinstance('abc',Iterable)) # True
print(isinstance([1,2,3,4],Iterable)) # True
print(isinstance(123,Iterable)) # False
4.迭代器对象
(1)有内置的 __next__() 方法的对象,执行该方法可以不依赖索引取值。
(2)有内置的 __iter__()方法的对象,执行迭代器的 __iter__()方法得到的依然是迭代器本身。
需要注意的是可迭代的对象,不一定是迭代器。
from collections import Iterable,Iterator
li = [1,2,3,4]
print(isinstance(li,Iterator)) # False
5.iter()
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。那我们可以通过iter()方法将可迭代的对象,转为迭代器。
注意:迭代器不可以通过下标取值,而是使用__next__()或者next()函数。但是只要超出迭代器的范围就会直接报错。且next()只能顺延调用,不能往前。
print(lis[0]) # 报错 not subscriptable
print(lis.__next__())
print(lis.__next__())
print(lis.__next__())
print(lis.__next__())
print(next(lis))
print(next(lis))
print(next(lis))
print(next(lis))
print(next(lis)) #报错 'list_iterator' object is not subscriptable
6.可迭代对象和迭代器区别
(1)可用于 for 循环的都是可迭代类型
(2)作用于next()都是迭代器类型
(3)list,dict,str,等都是可迭代的但不是迭代器,因为next()函数无法调用它们。可以通过iter()函数将它们转为迭代器
(4)python的for循环本质就是通过不断调用next()函数实现的
三.生成器
1.生成器定义:
在python中,一边循环一边计算的机制,称为生成器:generator。
为什么要有生成器呢?
列表所有数据都在内存中,如果有海量数据的话会非常消耗内存。
比如说:我们仅仅需要访问前面几个元素,但后面绝大多元素占用的内存就会浪费了。
那么生成器就是在循环的过程中根据算法不断推算出后续的元素,这样就不用创建整个完整的列表,从而节省大量的空间。
总而言之,就是当我们想要使用庞大数据,又想让它占用的空间少,那就使用生成器。
2.创建生成器
(1)生成器表达式:生成器表达式来源于迭代和列表解析的组合,生成器和列表类似,但是它使用的是()而不是[]。(与理论上的元组推导式类似)
g = (x for x in range(5))
print(g) # generator object
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
# 超出报错
print(next(g))
for i in g:
print(i)
3.生成器函数
当一个函数中包含 yield关键字,那么这个函数就不再是一个普通的函数,而是一个 generator。调用函数就是创建了一个生成器对象。其工作原理就是通过重复调用next()或者__next__()方法,直到捕获一个异常。
def yieldtest(number):
n = 0
# li = []
while n<number:
# li.append(n)
yield n
n+=1
res = yieldtest(3)
print(res) # generator object
print(next(res)) # 0
print(next(res)) # 1
print(next(res)) # 2
注意:yield返回的是一个值,并且记住这个返回值的位置,下次遇到next()调用时,代码会从yield的下一条语句开始i执行。与return的区别是,return返回的也是一个值,但是直接结束函数。
例如:实现斐波那契数列,除了第一个和第二个数之外,任何一个数都可以由前两个相加得到,代码如下:
def createNums():
print("-----func start-----")
a,b = 0,1
for i in range(5):
# print(b)
print("--1--")
yield b
print("--2--")
a,b = b,a+b
print("--3--")
print("-----func end-----")
g = createNums()
print(next(g))
print(next(g))
print(next(g))
print(next(g))
print(next(g))
4.send()函数
send()和next()一样,都能让生成器继续往下走一步(遇到yield返回),但send()能传一个值,这个值作为yield表达式整体的结果。
def test():
a1 = yield "hello"
print("---1---")
yield a1
res = test()
print(next(res)) # "hello"
print(res.send("world")) # "world"
也就是说,通过send方法可以强行修改上一个yield表达式值。
比如函数中有一个yield赋值,a1 = yield "hello",第一次迭代到这里会返回"hello",但是a1还没进行赋值。第二次迭代时,使用.send("world"),那么,就是相当于强行修改yield "hello"表达式的值为"world",所以yield a1结果为"world"。
5.迭代器与生成器
(1)生成器能做到迭代器能做的所有事
(2)而且因为生成器自动创建了iter()和next()方法,生成器显得简洁,而且高效。