迭代器
【一】迭代器介绍
- 迭代器就是用来迭代取值的工具,是重复反馈过程的程序
- 目的是为了更加逼近我们想要的目标和结果
- 每一次迭代得到的返回结果就是下一次迭代开始的初始值
num_list = [1,2,3,4,5,6]
count = 0
while count <len(num_list):
# 每一次使用的索引位置就是上一次+1后的索引位置
print(num_list[count])
count += 1
1
2
3
4
5
6
【二】可迭代对象
【1】什么是可迭代对象
- 可以通过列表的索引进行取值,但是如果一个数据没有索引的话
- 必须找到一种可以用索引也可以不用索引的方法来取值
【2】八大基本数据类型
补充
生成可迭代对象的两种方式
iter()
相当于
__iter__(数据)
迭代器对象迭代的方法的两种方式
迭代器对象.__next__()
next(迭代器对象)
数字类型
整数
age = 18
print(iter(age))
print(age.__iter__)
报错 'int' object is not iterable
浮点数
age = 18.5
print(iter(age))
print(age.__iter__)
报错 'float' object is not iterable
字符串类型
qwer = 'qewr'
print(iter(qwer))
print(qwer.__iter__)
输出
<str_iterator object at 0x0000021D016BA740>
<method-wrapper '__iter__' of str object at 0x0000021D0165D3B0>
列表类型
list = [1,2,3,4,5,6]
print(iter(list))
print(list.__iter__)
输出
<list_iterator object at 0x000001FA4D7097B0>
<method-wrapper '__iter__' of list object at 0x000001FA4D6B4E40>
字典类型
dict = {'q':'1','w':2}
print(iter(dict))
print(dict.__iter__)
输出
<dict_keyiterator object at 0x000001E457AED670>
<method-wrapper '__init__' of dict object at 0x000001E457AA1F40>
布尔类型
bool = True
print(iter(bool))
print(bool.__iter__)
报错 'bool' object is not iterable
元组类型
tuple = (1,2,3,4,5,6)
print(iter(tuple))
print(tuple.__iter__)
输出
<tuple_iterator object at 0x000001AE3656A740>
<method-wrapper '__init__' of tuple object at 0x000001AE36578940>
集合类型
set = {1,2,3,4,5,6}
print(iter(set))
print(set.__iter__)
输出
<set_iterator object at 0x000001E74BFF2080>
<method-wrapper '__init__' of set object at 0x000001E74C026DC0>
【3】总结
能.__iter__不报错的就是可迭代类型 ————>可迭代对象
可迭代类型
字符串、列表、元组、集合、字典
不可迭代类型
整数、浮点数、布尔
【三】迭代器对象
【1】什么是迭代器对象
# 如果调用obj.__iter__()返回的是一个可迭代对象
# 有的可迭代对象还有__next__()方法
# 迭代器对象实在可迭代对象(具有.__iter__()方法)的基础上具有.__next__()方法的对象
【2】八大基本数据类型(除了不可迭代)
(1)字符串
name = "qwer"
name_iter = name.__iter__()
print(name_iter)
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__()) # 会报错 most recent call last
<str_iterator object at 0x00000202DE74A740>
q
w
e
r
第五行报错
(2)列表
name = [1,2,3,4,5,6]
name_iter = name.__iter__()
print(name_iter)
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
<list_iterator object at 0x0000026B66C3A740>
1
2
3
4
5
(3)字典
得到的是键
name = {'q':1,'w':'2','e':'3','r':'4'}
name_iter = name.__iter__()
print(name_iter)
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
<dict_keyiterator object at 0x000001C4B92DD670>
q
w
e
r
(4)元组
name = (1,2,3)
name_iter = name.__iter__()
print(name_iter)
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
<tuple_iterator object at 0x000001D9C593A740>
1
2
3
(5)集合
name = {1,2,3,4,5,6}
name_iter = name.__iter__()
print(name_iter)
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
print(name_iter.__next__())
<set_iterator object at 0x00000234968D2000>
1
2
3
4
【3】总结
具有__iter__() 和 __next__()方法的对象是可迭代对象
-
在八大基本数据类型中,除了数字和布尔类型,其他都是迭代器对象
-
迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器对象
-
迭代器对象是同时具有上述两个方法的对象
-
可迭代对象只需有第一个方法既是可迭代对象
【四】迭代器的优缺点
- 优点
- 不使用索引取值(例如字典不支持索引取值)
- 取到值后会保存当前状态,下次从当前位置开始继续取值
- 缺点
- 除非取值取到尽头,否则永远不知道终止索引在哪里
- 只能取一次记一次位置,下一次的其实位置是上一次的终止位置,想回到开头 回不去
- 调用 next 取值的前提是 已经生成并且得到了一个迭代器对象 iter_obj
- 迭代同一个对象只能重新创建
name = 'dr'
name_iter = name.__iter__()
print(next(name_iter))
print(next(name_iter))
name_iter = name.__iter__() # 要重复取值必须重新创建迭代器对象
print(next(name_iter))
d
r
d
生成器
【一】什么是生成器
-
生成器是一种特殊的迭代器
-
在需要的时候给你数据,不需要就不会给数据
-
for循环 range(10) 可以把生成的数字取出来
-
数据量过大的话 读取数据内存满,电脑卡死
-
生成器 ---> 一次取...行 --->处理完这些数据后--->再取...行
例子 for i in fp:
【二】生成器的创建方式
【1】列表推导式
print([i for i in range(10)])
# 如果将列表生成式外面的列表换成元组,则会生成一个生成器对象
print((i for i in range(10)))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
<generator object <genexpr> at 0x0000020E358F8430>
【2】yiled关键字
def add(i):
yield i
# add(2)进入到add函数,将原本的函数对象转换为生成器对象
res = add(2)
print(res)
# 想取值只能使用next来迭代取值
print(res.__next__())
<generator object add at 0x00000155DB1E8430>
2
def add(i):
# i = 1
while True:
yield i # 第一次next
res = add(1)
print(res)
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())
res = add(3)
print(res.__next__())
<generator object add at 0x000001EFDF0CEAB0>
1
1
1
1
3
补充
在第一次调用生成器时,`yield`语句会在赋值操作符`=`的右边停下。
考虑下面的代码:
```python
def my_generator():
x = yield
print("Received:", x)
gen = my_generator()
```
当你执行`gen = my_generator()`时,生成器`my_generator`并没有开始执行。相反,它返回了一个生成器对象`gen`。此时,`my_generator`函数中的代码并没有运行。
然后,当你调用`gen.__next__()`或`next(gen)`时,生成器才会开始执行。它会执行到`x = yield`这一行,但暂停在`yield`右边,等待接收一个值。这个值会被赋给`x`。因此,第一次调用`yield`语句时,生成器会停在赋值操作符`=`的右边。
【三】生成器案例
def outer():
print("开始吃饭")
while True:
food = yield # 等同于yield(food)
print(f"做了{food},吃{food}")
res = outer()
print(res)
print(res.__next__())
print(res.__next__())
<generator object outer at 0x00000183F2538430>
开始吃饭
None
做了None,吃None
None # 原因是在生成器内部走完了上面代码,又回到了yield 没有返回值
yield语句在生成器函数中充当了暂停和恢复执行的标记,同时也充当了返回值的功能。当生成器函数执行到yield语句时,它会暂停执行并将yield后面的表达式作为返回值返回给调用方。在上述代码中food为yield的后面的表达式
向生成器中传值
send() 传值后会再往下走一步
res = outer()
print(res)
print(res.__next__())
res.send('炒饼') # 向 yield 传值并且让生成器向下走一下
print(res.__next__())
res.send('炒饭')
<generator object outer at 0x000002A8C99E8430>
开始吃饭
None
做了炒饼,吃炒饼
做了None,吃None
None
做了炒饭,吃炒饭
【四】装饰器 + 生成器
def init_iter(func):
def inner(*args,**kwargs):
# g 是得到的生成器对象
g = func(*args,**kwargs)
# 调用自己生成器往下走
next(g)
# 走回来的返回值返回出去
return g
return inner
@init_iter
def outer():
print("开始吃饭")
while True:
# yield food
food = yield
print(f"做了{food},吃{food}")
res = outer()
res.send('炒米粉')
res.send('炒fan')
开始吃饭
做了炒米粉,吃炒米粉
做了炒fan,吃炒fan
【五】生成器内部修改可变数据类型
def init_iter(func):
def inner(*args,**kwargs):
# g 是得到的生成器对象
g = func(*args,**kwargs)
# 调用自己生成器往下走
next(g)
# 走回来的返回值返回出去
return g
return inner
@init_iter
def outer():
print("开始吃饭")
list = []
while True:
# yield food
food = yield
list.append(food) 因为没有退出循环,所以会把新值一直加到列表中
print(f"做了{food},吃{food}")
print(list)
res = outer()
res.send('炒米粉')
res.send('炒fan')
开始吃饭
做了炒米粉,吃炒米粉
['炒米粉']
做了炒fan,吃炒fan
['炒米粉', '炒fan']
【六】yield + next 搭配着使用
仿照循环自己构建循环函数
for i in range(5):
print(i)
def my_range(start, stop, step):
'''
:param start: 0
:param stop: 5
:param step: 1
:return:
'''
print("start")
while start < stop:
yield start
start += step
print("end")
res = my_range(0, 5, 1)
print(res) # <generator object my_range at 0x000002DF0361CBA0>
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())
print(res.__next__())
# 这里会报错 ---> 没有可迭代的值可以被获取了
print(res.__next__()) # StopIteration
def init_iter(func):
def inner(*args, **kwargs):
try:
generator = func(*args, **kwargs)
next(generator)
return generator
except StopIteration:
pass
return inner
def range_(start, stop, step):
while start < stop:
yield start
start += step
# for 循环内部做了异常捕获
for i in range_(0,5,1):
print(i)
def my_range(start, stop, step):
def range_(start, stop, step):
while start < stop:
yield start
start += step
res = range_(start, stop, step)
while True:
try:
print(res.__next__())
except StopIteration:
break
res = my_range(start=1, stop=5, step=1)
res
0
1
2
3
4
1
2
3
4
标签:__,.__,name,迭代,生成器,iter,next,print
From: https://www.cnblogs.com/yi416/p/18204841