首页 > 其他分享 >迭代器、生成器

迭代器、生成器

时间:2024-05-21 20:07:32浏览次数:15  
标签:__ .__ name 迭代 生成器 iter next print

迭代器

【一】迭代器介绍

  • 迭代器就是用来迭代取值的工具,是重复反馈过程的程序
  • 目的是为了更加逼近我们想要的目标和结果
  • 每一次迭代得到的返回结果就是下一次迭代开始的初始值
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__()方法的对象是可迭代对象
  • 在八大基本数据类型中,除了数字和布尔类型,其他都是迭代器对象

  • 迭代器对象一定是可迭代对象,可迭代对象不一定是迭代器对象

  • 迭代器对象是同时具有上述两个方法的对象

  • 可迭代对象只需有第一个方法既是可迭代对象

【四】迭代器的优缺点

  1. 优点
    • 不使用索引取值(例如字典不支持索引取值)
    • 取到值后会保存当前状态,下次从当前位置开始继续取值
  2. 缺点
    • 除非取值取到尽头,否则永远不知道终止索引在哪里
    • 只能取一次记一次位置,下一次的其实位置是上一次的终止位置,想回到开头 回不去
    • 调用 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

相关文章

  • Vue3+nanoid编写字符串ID生成器
    Vue3+nanoid编写字符串ID生成器中文介绍:https://github.com/ai/nanoid/blob/HEAD/README.zh-CN.md一个小巧、安全、URL友好、唯一的JavaScript字符串ID生成器。“一个惊人的无意义的完美主义水平,这简直让人无法不敬佩。”小巧. 116字节(经过压缩和Brotli处理)。没有依......
  • 二叉树 | 迭代法 102.二叉树的层序遍历 429. N 叉树的层序遍历 226.翻转二叉树
    leetcode102.二叉树的层序遍历题目102.二叉树的层序遍历给你二叉树的根节点root,返回其节点值的层序遍历。(即逐层地,从左到右访问所有节点)。解题思路实现代码classTreeNode:def__init__(self,val=0,left=None,right=None):self.val=valse......
  • Python学习迭代器(Iterator)
    一、可迭代的对象(Iterable)1、定义:可以直接用在循环的数据类型,如list,tuple,dict,set,str,还有generator(生成器),和带yield的函数,这些直接可以用在循环的对象统称为可迭代对象(Iterable)fromcollectionsimportIterableprint(isinstance([],Iterable))print(isin......
  • python中的生成器(generator)学习
    生成器(Generator)是一种特殊的函数,可以用于迭代地生成一系列值,而不需要一次性生成所有值并将它们存储在内存中。生成器在需要时逐个生成值,并在生成值后暂停执行,保留函数的状态,以便下次调用时能够从停止的地方继续执行。生成器函数使用yield语句来定义,而不是常规函数中的return......
  • python中的装饰器,迭代器,生成器之间的关系
    一、装饰器装饰即修饰,意指为其他函数添加新功能;装饰器的本质就是函数作用是为其他函数添加新功能,如计算该函数运行时长装饰器遵循原则:1.不修改被装饰函数的源代码(开放封闭原则)2.为被装饰函数添加新功能后,不能修改被修饰函数的调用方式装饰器的实现=高阶函数+函数嵌套+......
  • JAVA版的代码生成器gen
    自己安装方式dockerpullregistry.cn-hangzhou.aliyuncs.com/tanghc/gen:latest 下载完毕后,执行 dockerrun--namegen--restart=always\-p6969:6969\-eJAVA_OPTS="-server-Xms64m-Xmx64m-DLOCAL_DB=/opt/gen/gen.db"\-v/opt/gen/:/opt/gen/\......
  • 【强化学习】A grid world 值迭代算法 (value iterator algorithm)
    强化学习——值迭代算法代码是在jupyternotebook环境下编写只需要numpy和matplotlib包。此代码为学习赵世钰老师强化学习课程之后,按照公式写出来的代码,对应第四章第一节valueiteratoralgorithm可以做的实验:调整gama值观察策略的变化调整惩罚值(fa)的大小观察......
  • 易易二维码,多功能在线文件预览与二维码生成器
    一、引言在数字化时代,信息的传递与分享变得尤为重要。无论是商务文件、个人文档,还是活动宣传、产品推广,都需要一种高效、便捷的方式来进行信息的展示与分享。易易二维码,作为一款集多WPS、Office文件在线预览、二维码设计、二维码在线报名、网址、图文、文件转二维码以及二维码浏......
  • 随机数生成器,支持Udint和Char两个格式
    读取本地时间的纳秒时间,计算取余数得到随机数1.变量声明,定义2.模式选择,支持UDINT和CHARCHAR仓库定义了72个字符,由自定的字符串长度决定的char没有从0开始;PLC字符串长度为(2+n);第一个byte保存的是最大长度,第二个是当前长度,后面才是用户指定的长度,如string[78]总占用长度80......
  • Java学设计模式之迭代器模式
    一、迭代器模式概念1.1什么是迭代器模式迭代器模式是一种行为型设计模式,它提供了一种方法来顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。简单来说,迭代器模式可以让你遍历一个集合对象,而无需了解其内部结构。结构迭代器(Iterator):定义了访问和遍历元素的接......