Python迭代器与生成器
目录
1.0 python推导式
1.1 什么是推导式?
推导式comprehensions(又称解析式),是Python的一种独有特性。推导式是可以从一
个数据序列构建另一个新的数据序列的结构体。
共有三种推导,在Python2和3中都有支持:
1.1.1 列表推导式
列表(list)推导式 ---》用 [] 生成list
基本格式:variable = [out_exp_res for out_exp in input_list if out_exp == 2]
•
out_exp_res
: 列表生成元素表达式,可以是有返回值的函数。
•
for out_exp in input_list
: 迭代input_list将out_exp传入out_exp_res表达式中。
•
if out_exp == 2
: 根据条件过滤哪些值
示例:打印20以内不是3的倍数的数的平方
方法1:
tmp = []
for i in range(20):
if i % 3:
tmp.append(i*i)
print(tmp)
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-08-迭代器与生成器/01.推导式.py
[1, 4, 16, 25, 49, 64, 100, 121, 169, 196, 256, 289, 361]
[1, 4, 16, 25, 49, 64, 100, 121, 169, 196, 256, 289, 361]
Process finished with exit code 0
列表推导式写法:
result = [ i*i for i in range(20) if i % 3 ]
print(result)
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-08-迭代器与生成器/01.推导式.py
[1, 4, 16, 25, 49, 64, 100, 121, 169, 196, 256, 289, 361]
Process finished with exit code 0
示例:使用列表推导式输出200以内,开平方是整数的数
result = [i for i in range(200) if math.sqrt(i).is_integer()]
print(result)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196]
示例:将列表里的小数保留两位小数输出到列表
lst1 = [2.45345, 4.3454325, 9, 82.234321, 83.841234]
lst2 = [float("%0.2f" % j) for j in lst1 if j]
print(lst2)
['2.45', '4.35', '9.00', '82.23', '83.84']
示例:找到嵌套列表中名字含有2个'e'的所有名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva', 'Elven']]
方法1:
for i in names:
for j in i:
if j.lower().count('e') >= 2:
print(j)
Jefferson
Wesley
Steven
Jennifer
Elven
列表推导式:
result1 = [j for i in names for j in i if j.lower().count('e') >= 2]
print(result1)
['Jefferson', 'Wesley', 'Steven', 'Jennifer', 'Elven']
#################################
1.1.2 集合推导式
因为集合的特性,集合推导式自带去重功能。
# 集合推导式 --》 天生去重
str1 = "qwerqwerasasfdfd"
print(set(str1))
print({i for i in str1})
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-08-迭代器与生成器/01.推导式.py
{'e', 'f', 'q', 'd', 'a', 'w', 's', 'r'}
{'e', 'f', 'q', 'd', 'a', 'w', 's', 'r'}
#################################
’1.1.3 字典推导式
字典(dict)推导式
字典推导和列表推导的使用方法是类似的,只不中括号该改成大括号。
基本格式:variable = {out_key:out_value for out_key,out_value in input_list if out_exp == 2}
•
out_key:
返回字典结果的key
•
out_value:
返回字典结果的value
•
for out_key,out_value in input_list:
迭代input_list将out_exp传入out_exp_res表达式中。
•
if out_exp == 2:
根据条件过滤哪些值可以。
示例:
# 字典推导式
print({x: y for x, y in [('a', 1), ('b', 2)]})
# 统计字符串中每一个字符出现的字数
str1 = "aleiafesl5e-e;'ree2f5a43"
print({x: str1.count(x) for x in str1})
# 过滤长度小于三的字符串,并将剩下的转换成大写字母
q1 = ['a', 'ab', 'abc', 'abcd', 'abcde']
print([i.upper() for i in q1 if len(i) >= 3])
# 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元组列表
result = [(x, y) for x in range(6) for y in range(6) if x % 2 == 0 and y % 2 ==1]
print(result)
# 快速跟换key和value
q3 = {'a': 10, 'b': 34}
print({q3[x]: x for x in q3})
# 合并大小写对应的value值,将key统一写成小写
q4 = {'B': 3, 'a': 1, 'b': 6, 'c': 3, 'A': 4}
result2 = {x.lower(): q4.get(x.lower(), 0) + q4.get(x.upper(), 0) for x, y in q4.items()}
print(result2)
str1 = "aleiafesl5e-e;'ree2f5a43"
tmp = {}
for i in str1:
tmp[i] = tmp.get(i, 0) + 1
print(tmp)
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-08-迭代器与生成器/01.推导式.py
{'a': 1, 'b': 2}
{'a': 3, 'l': 2, 'e': 6, 'i': 1, 'f': 2, 's': 1, '5': 2, '-': 1, ';': 1, "'": 1, 'r': 1, '2': 1, '4': 1, '3': 1}
['ABC', 'ABCD', 'ABCDE']
[(0, 1), (0, 3), (0, 5), (2, 1), (2, 3), (2, 5), (4, 1), (4, 3), (4, 5)]
{10: 'a', 34: 'b'}
{'b': 9, 'a': 5, 'c': 3}
{'a': 3, 'l': 2, 'e': 6, 'i': 1, 'f': 2, 's': 1, '5': 2, '-': 1, ';': 1, "'": 1, 'r': 1, '2': 1, '4': 1, '3': 1}
Process finished with exit code 0
#################################
2.0 python可迭代对象
之前只学习了一部分内容的时候说过,可以for循环的都属可迭代对象,那么有哪些常见可迭代对象?
list, set, dict,tuple,str,file等这些都属容器数据结构
#################################
2.1 什么是容器?:
容器(container)
容器是一种
把多个元素组织在一起
的数据结构,容器中的元素
可以逐个地迭代获取
,可以用
in, not
in关键字判断
元素是否包含在容器中。
通常这类数据结构把所有的元素存储在内存中(也有一些特例,并不是所有的元素都放在内存,比如
迭代器和生成器对象)
#################################
2.2 可迭代对象
什么是可迭代对象?
凡是实现了__iter__方法,并且可以返回一个迭代器的对象都可以称之为可迭代对象。
str1 = "abc"
# 一般来说容器类型都是可迭代对象
print(dir(str1))
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-08-迭代器与生成器/02.迭代器和生成器.py
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
print(hasattr(str1, "__iter__"))
True
一般来说,容器类型的数据结构都是可迭代对象。
例:这里有一个类 A,它有__iter__方法,但是没有返回迭代器,所以它不是可迭代对象
class A:
def __iter__(self):
return None
#################################
2.2.1 判断一个对象是不是可迭代对象
使用iterable判断
from collections import Iterable
a='abc'
b = [1,2,3]
c=(4,5,6)
d={"name": 'tom', "age": 22}
if isinstance(a, Iterable):
print("a是可迭代对象")
if isinstance(b, Iterable):
print("b是可迭代对象")
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-08-迭代器与生成器/01.推导式.py
a是可迭代对象
b是可迭代对象
#################################
3.0 迭代器(iterator)
什么是迭代器?
迭代器是
有状态的
,可以被next()调用,函数调用并不断返回下一 个值的对象称为迭代(Iterator)。
任何实现了__iter__()和__next__()都是迭代器
•
__iter__():返回迭代器自身
•
__next__():返回容器中的下一个值
•
如果容器中没有更多元素了,则抛出
StopIteration
异常
•
(for循环取数据遇到StopIteration时,会退出循环)
•
所有的Iterable均可以通过内置函数iter()来转变为Iterator。
#################################
3.1 编写迭代器,实现range
class Myrange():
def __init__(self, num):
self.num = num
self.start = 0
def __iter__(self):
self.cur_val = self.start - 1
return self
def __next__(self):
self.cur_val += 1
if self.cur_val < self.num:
return self.cur_val
else:
raise StopIteration
for i in Myrange(10):
print(i)
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-08-迭代器与生成器/02.迭代器和生成器.py
0
1
2
3
4
5
6
7
8
9
#################################
3.2 编写迭代器,实现斐波拉契数列
class Fblq():
n = 0
def __init__(self, num):
self.num = num
self.next = 0
self.start = 1
self.middle = 1
def __iter__(self):
return self
def __next__(self):
self.n += 1
if self.n == 1 or self.n == 2:
return self.middle
if self.next <= self.num:
self.next = self.start + self.middle
self.middle = self.start
self.start = self.next
return self.next
else:
raise StopIteration
for i in Fblq(6):
print(i)
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-08-迭代器与生成器/02.迭代器和生成器.py
1
1
2
3
5
8
#################################
4.0 生成器(generator)
4.1 什么是生成器?
生成器算得上是Python语言中最吸引人的特性之一,生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要手动编写__iter__()和__next__()方法,只需要一个yiled关键字。
•
生成器一定是迭代器(反之不成立)
•
因此任何生成器也是以一种懒加载的模式生成值(惰性求值)
#################################
4.2 生成器表达式
生成器表达式
•
使用()生成generator,
将俩表推导式的[]改成()即可得到生成器。
•
列表推导式与生成器表达式,定义和使用非常类似,但是,在(大量数据处理时)性能上相
差很大
yield关键字
包含yield表达式的函数是特殊的函数,叫做
生成器函数(generator function)
,被调用时将返回一个
迭代器(iterator),调用时可以使用next或send(msg)
•
一个生成器中可以有多个yield
•
一旦遇到yield,就会保存当前状态,然后返回yield后面的值
def get_content():
print("start yield...")
yield 3
print("second yield")
yield 4
print("end...")
g1 = get_content()
print(dir(g1))
print('*'*20)
print(next(g1))
print('*'*20)
print(next(g1))
print('*'*20)
print(next(g1))
********************
start yield...
3
********************
second yield
4
********************
end...
Traceback (most recent call last):
File "E:\tlbb\2022-07-08-迭代器与生成器\02.迭代器和生成器.py", line 115, in <module>
print(next(g1))
StopIteration
Process finished with exit code 1
使用生成器编写range
def Myrange(num):
i = 0
while i < num:
yield i
i += 1
for i in Myrange(3):
print(i)
E:\python\python3.9.1\python.exe E:/tlbb/2022-07-08-迭代器与生成器/02.迭代器和生成器.py
0
1
2
Process finished with exit code 0
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?