
【千锋教育干货暴击】
如果你想更好的学习Python乃至转行,弯道超车,快人一步!本课程零基础即可加入学习,抓住大数据、机器学习、人工智能时代的红利,开启你的第一行代码吧!
↓ ↓ ↓
千锋教育Python教程_700集零基础Python入门到精通教程(保姆级新手教程)
千锋教育Python教程全套_python零基础入门到精通(学完可达到Python工程师水平)

现在我们有一组列表数据teas = ['草莓奶茶','香芋西米露','木瓜奶茶','香芋奶茶','柠檬奶茶','红豆西米露','烧仙草','雪融烧仙草','木瓜奶昔','芒果奶昔'],现在我们需要把带奶茶两个字的找出来,你会怎么做?
teas = ['草莓奶茶','香芋西米露','木瓜奶茶','香芋奶茶','柠檬奶茶','红豆西米露', '烧仙草', '雪融烧仙草','木瓜奶昔','芒果奶昔']
milk_tea = []
for tea in teas:
if '奶茶' in tea:
milk_tea.append(tea)
print(milk_tea) 当然for循环遍历判断没有问题!其实你也可以了解了解列表推导式。
看看它的基本概念都是什么?
列表解析式(List comprehension)或者称为列表推导式,是 Python 中非常强大和优雅的方法。它可以基于现有的列表做一些操作,从而快速创建新列表。它的格式是:

比如说:
list1 = [x*x for x in range(100)]
print(list)
#等价于
list2 = []
for x in range(100):
list2.append(x*x)
print(list2) 大家可以将上面的代码的两种,进行一下速度对比。

如果加上判断条件则
list1 = [x*x for x in range(10) if x%2==0]
print(list)
#等价于
list2 = []
for x in range(10):
if x%2 == 0:
list2.append(x*x)
print(list2) 因此上面的奶茶的代码就可以改成如下表示:
milk_tea = [tea for tea in teas if '奶茶' in tea]
print(milk_tea) 案例:如果结合os模块,我们还可以找出指定目录的文件
# 遍历当前目录下的文件,并在把后缀为.py的放在列表中
import os
files=os.listdir("./")
file_list=[name for name in files if name.endswith(".py")]
print(file_list) 给大家留个小小的问题尝试自己解决下哦!

当然我们还可以if与else结合使用
# 将列表中的年龄小于等于15岁的都加1岁
ages = [17,13,10,18,20,14,15]
ages = [age if age>15 else age+1 for age in ages ]
print(ages) 双层for循环的列表推导式也是可以的
list1=[(x,y) for x in range(5,9) for y in range(1,5)]
print(list1) 猜一猜上面的代码结果是什么?
大家不要以为只有列表推导式,其实还有字典推导式,了解一下吧!格式如下:
d = {key: value for (key, value) in iterable}
# 字典推导式
dict1 = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D'}
newdict = {value:key for key, value in dict1.items()}
print(newdict) # 结果:{'A':'a','B':'b','C':'c','D':'d'} 另外集合推导式与列表推导式类似,里面是不存在重复元素的。集合的外层符号式:[],而集合的推导式式:{}。即:
变量名 = {表达式 for 变量 in 列表 } 大家经常在看源码的时候,经常会看到或者这个单词,什么意思呢?

接下来我们就来介绍下它们。首先我们说Iterable是表示可迭代的意思,那如何判断某个数据类型是可迭代的呢?
需要从collections模块中导入了Iterable类,并结合了isinstance(A,B)进行判断,isinstance(A,B)函数是系统的内置函数表示A是否是B的实例,返回值是布尔类型的。
from collections import Iterable
list1 = [1, 4, 7, 8, 8]
f = isinstance(list1, Iterable)
print(f) # True
f = isinstance('abc', Iterable)
print(f) # True
f = isinstance(100, Iterable)
print(f) # False
我们发现元组,列表, 集合, 字典, 字符串都是可迭代的,但是整型,浮点型就不是可迭代的。
所以大家就知道上面图片中的max()和min()函数中的iterable表示的是可迭代的对象。
那下面的next()函数中的iterator表示什么意思?迭代器
迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。特点如下:

那是不是可迭代的就是迭代器呢?
from collections.abc import Iterator
list1 = [1, 4, 7, 8, 8]
f = isinstance(list1, Iterator)
print(f) # False
f = isinstance('abc', Iterator)
print(f) # False
f = isinstance(100, Iterator)
print(f) # False 也可以使用next()这个内置函数测试,可以被next()函数调用并不断返回下一个值的对象可以认为是迭代器:Iterator。
list1 = [1, 4, 7, 8, 8]
result = next(list1)
print(result) 大家发现有报错:
TypeError: 'list' object is not an iterator 大家发现两种方式的判断列表都不是迭代器,那可迭代的可以变成迭代器吗?因为只有变成迭代器才可以一个一个的取元素。
答案是可以的!使用iter(),只需要将可迭代的对象放到这个函数中就可以变成迭代器了。
list1 = [1, 2, 3, 4, 5]
list1 = iter(list1) # 通过iter()函数将可迭代的变成了一个迭代器
print(next(list1)) 此时就不会报错了。
通过列表推导式,我们可以直接创建一个列表。但是受到内存限制,列表容量肯定是有限的。并且如果创建一个包含100万个元素的列表,还会占用很大的存储空间,而我们也不会一下就用到那么多列表中的元素,这样此列表就会长时间的占用大量的内存。那有没有不必创建完整的list,用的时候就可以依次向后取到元素呢?有的!在Python中,这种一边循环一边计算的机制,称为生成器:generator。
简单一句话:我又想要得到庞大的数据,又想让它占用空间少,那就用生成器!
python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。
如何创建生成器
创建生成器的方式有两种:
类似列表推导式的格式创建
函数+yield创建 类似列表推导式方式创建
现在有个需求,现有列表 [0,1,2,3,4,5,6,7,8,9],要求你把列表里面的每个值加1,你怎么实现呢?用上面提到的列表推导式如下:
list1 = [x+1 for x in range(10)]
print(list1) 大家看清楚了,我现在下面的代码换符号了哦,将[]换成了()
list1 = (x+1 for x in range(10))
print(list1) 两者的结果是什么呢?

第二个打印出来却是<generator object at 0x10e630350>,generator object就表示此时是一个生成器对象。但是里面的元素我们是没有看到的。
那如何看到里面的元素呢?这时我们就可以通过next()函数了。next()函数的作用就是获取一个generator生成器的元素,如果想获取多个要多次调用。因此:
list1 = (x+1 for x in range(10))
print(list1)
print(next(list1))
print(next(list1))
......
print(next(list1)) 每次调用next(list1)就计算它的下一个元素的值,直到计算出最后一个元素,但是此时你还调用next(list1),next(list1)取不到值了就会抛出异常StopIteration,其实这样不断调用是一个不好的习惯,正确的方法是使用for循环,因为generator也是可迭代对象:
for l in list1:
print(l) generator非常强大,如果推算的算法比较复杂,用类似列表推导式的for循环无法实现的时候,还可以用函数来实现。
函数+yiled创建
来看一下下面的函数:
def yield_test(n):
for i in range(n):
print('---->i=',i)
print("Done.")
print(yield_test)
g = yield_test(5)
print(g) 结果:

yield_test调用的返回值是一个None。接下来我们在函数中添加一个关键字yield,再看一下结果。
def yield_test(n):
for i in range(n):
yield i*2
print('---->i=',i)
print("Done.")
print(yield_test)
g = yield_test(5)
print(g) 结果:

可以看到print(g)打印的内容是一个生成器对象。说明我们在函数添加关键字之后再次调用函数就变成了生成器了。如果想获取里面的内容,我们可以配合for循环或者next()函数使用,根据自己的需求。
def yield_test(n):
for i in range(n):
yield i*2
print('---->i=',i)
print("Done.")
print(yield_test)
g = yield_test(5)
for i in g:
print(i) 结果:

为什么是打印一个数字底下跟一个带箭头的打印呢?yield关键字的作用又是什么呢?
yield关键字可以认为是:暂停 + return 的作用。
每次循环遇到yield暂停,将yield后面的数字返出,当下一轮循环的时候从暂停处继续向下执行,直到再次遇到yield关键字,程序又暂停并将后面的值返出,依次类推的执行。更加清楚的理解建议大家可以先不使用for循环遍历生成器对象,而是调用几次next(g)观察结果会加清晰明了。
下面我们用生成器写一个斐波那契数列。
def fib(length):
a, b = 0, 1
n = 0
while n < length:
yield b # return b + 暂停
a, b = b, a + b
n += 1
return '没有更多元素!!!'
g = fib(8)
print(next(g))
print(next(g))
print(next(g))
...... 当然可以使用next()系统函数获取生成器的元素,还可以使用生成器对象的__next__完成.
生成器方法:

def gen():
i = 0
while i < 5:
temp = yield i # return i + 暂停
print('temp:', temp)
for x in range(temp):
print('--------->', x)
print('****************')
i += 1
return '没有更多的数据'
g = gen()
# print(next(g))
# print(next(g))
# print(next(g))
# g.__next__()
print(g.send(None))
n1 = g.send(3)
print('n1:', n1)
n2 = g.send(5)
print('n2:', n2) 大家分析下上面的代码结果是什么呢?自己动手试一试吧!
最后给大家一张生成器与迭代器的关系图:


需要资料也可以关注微信公众号:Python专栏,事不宜迟,一起进步吧!
