菜鸟教程 -- 学的不仅是技术,更是梦想!

Python 3 教程
Python3 教程 Python3 简介 Python3 环境搭建 Python3 VScode Python3 基础语法 Python3 基本数据类型 Python3 数据类型转换 Python3 解释器 Python3 注释 Python3 运算符 Python3 数字(Number) Python3 字符串 Python3 列表 Python3 元组 Python3 字典 Python3 集合 Python3 条件控制 Python3 循环语句 Python3 编程第一步 Python3 推导式 Python3 迭代器与生成器 Python3 with Python3 函数 Python3 lambda Python3 装饰器 Python3 数据结构 Python3 模块 Python __name__ Python3 输入和输出 Python3 File Python3 OS Python3 错误和异常 Python3 面向对象 Python3 命名空间/作用域 Python 虚拟环境的创建 Python 类型注解 Python3 标准库概览 Python3 实例 Python 测验

Python3 高级教程

Python3 正则表达式 Python3 CGI编程 Python3 MySQL(mysql-connector) Python3 MySQL(PyMySQL) Python3 网络编程 Python3 SMTP发送邮件 Python3 多线程 Python3 XML 解析 Python3 JSON Python3 日期和时间 Python3 内置函数 Python3 MongoDB Python3 urllib Python uWSGI 安装配置 Python3 pip Python3 operator Python math Python requests Python random Python OpenAI Python 有用的资源 Python AI 绘画 Python statistics Python hashlib Python 量化 Python pyecharts Python selenium 库 Python 爬虫 Python Scrapy 库 Python Markdown Python sys 模块 Python Pickle 模块 Python subprocess 模块 Python queue 模块 Python StringIO 模块 Python logging 模块 Python datetime 模块 Python re 模块 Python csv 模块 Python threading 模块 Python asyncio 模块 Python PyQt Python for 循环 Python while 循环
(追記) (追記ここまで)

Python3 迭代器与生成器


迭代器

迭代是 Python 最强大的功能之一,是访问集合元素的一种方式。

迭代器是一个可以记住遍历的位置的对象。

迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

迭代器有两个基本的方法:iter()next()

字符串,列表或元组对象都可用于创建迭代器:

实例(Python 3.0+)

>>> list=[1,2,3,4]
>>> it = iter(list) # 创建迭代器对象
>>> print (next(it)) # 输出迭代器的下一个元素
1
>>> print (next(it))
2
>>>

迭代器对象可以使用常规for语句进行遍历:

实例(Python 3.0+)

#!/usr/bin/python3list=[1,2,3,4]it = iter(list)# 创建迭代器对象forxinit: print(x, end="")

执行以上程序,输出结果如下:

1 2 3 4

也可以使用 next() 函数:

实例(Python 3.0+)

#!/usr/bin/python3importsys# 引入 sys 模块list=[1,2,3,4]it = iter(list)# 创建迭代器对象whileTrue: try: print(next(it))exceptStopIteration: sys.exit()

执行以上程序,输出结果如下:

1
2
3
4

创建一个迭代器

把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() 与 __next__() 。

如果你已经了解的面向对象编程,就知道类都有一个构造函数,Python 的构造函数为 __init__(), 它会在对象初始化的时候执行。

更多内容查阅:Python3 面向对象

__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。

__next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。

创建一个返回数字的迭代器,初始值为 1,逐步递增 1:

实例(Python 3.0+)

classMyNumbers: def__iter__(self): self.a = 1returnselfdef__next__(self): x = self.aself.a += 1returnxmyclass = MyNumbers()myiter = iter(myclass)print(next(myiter))print(next(myiter))print(next(myiter))print(next(myiter))print(next(myiter))

执行输出结果为:

1
2
3
4
5

StopIteration

StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。

在 20 次迭代后停止执行:

实例(Python 3.0+)

classMyNumbers: def__iter__(self): self.a = 1returnselfdef__next__(self): ifself.a <= 20: x = self.aself.a += 1returnxelse: raiseStopIterationmyclass = MyNumbers()myiter = iter(myclass)forxinmyiter: print(x)

执行输出结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

生成器

在 Python 中,使用了 yield 的函数被称为生成器(generator)。

yield 是一个关键字,用于定义生成器函数,生成器函数是一种特殊的函数,可以在迭代过程中逐步产生值,而不是一次性返回所有结果。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

当在生成器函数中使用 yield 语句时,函数的执行将会暂停,并将 yield 后面的表达式作为当前迭代的值返回。

然后,每次调用生成器的 next() 方法或使用 for 循环进行迭代时,函数会从上次暂停的地方继续执行,直到再次遇到 yield 语句。这样,生成器函数可以逐步产生值,而不需要一次性计算并返回所有结果。

调用一个生成器函数,返回的是一个迭代器对象。

下面是一个简单的示例,展示了生成器函数的使用:

实例

defcountdown(n): whilen > 0: yieldnn -= 1# 创建生成器对象generator = countdown(5)# 通过迭代生成器获取值print(next(generator))# 输出: 5print(next(generator))# 输出: 4print(next(generator))# 输出: 3# 使用 for 循环迭代生成器forvalueingenerator: print(value)# 输出: 2 1

以上实例中,countdown 函数是一个生成器函数。它使用 yield 语句逐步产生从 n 到 1 的倒数数字。在每次调用 yield 语句时,函数会返回当前的倒数值,并在下一次调用时从上次暂停的地方继续执行。

通过创建生成器对象并使用 next() 函数或 for 循环迭代生成器,我们可以逐步获取生成器函数产生的值。在这个例子中,我们首先使用 next() 函数获取前三个倒数值,然后通过 for 循环获取剩下的两个倒数值。

生成器函数的优势是它们可以按需生成值,避免一次性生成大量数据并占用大量内存。此外,生成器还可以与其他迭代工具(如for循环)无缝配合使用,提供简洁和高效的迭代方式。

执行以上程序,输出结果如下:

5
4
3
2
1

以下实例使用 yield 实现斐波那契数列:

实例(Python 3.0+)

#!/usr/bin/python3importsysdeffibonacci(n): # 生成器函数 - 斐波那契a, b, counter = 0, 1, 0whileTrue: if(counter > n): returnyieldaa, b = b, a + bcounter += 1f = fibonacci(10)# f 是一个迭代器,由生成器返回生成whileTrue: try: print(next(f), end="")exceptStopIteration: sys.exit()

执行以上程序,输出结果如下:

0 1 1 2 3 5 8 13 21 34 55
AI 思考中...

10 篇笔记 写笔记

  1. #0

    cowpea

    115***[email protected]

    278

    来看一下有yield和没有yield的情况会对生成器了解多点:

    第一种:使用 yield

    #!/usr/bin/python3
    import sys
    def fibonacci(n,w=0): # 生成器函数 - 斐波那契
     a, b, counter = 0, 1, 0
     while True:
     if (counter > n): 
     return
     yield a
     a, b = b, a + b
     print('%d,%d' % (a,b))
     counter += 1
    f = fibonacci(10,0) # f 是一个迭代器,由生成器返回生成
    while True:
     try:
     print (next(f), end=" ")
     except :
     sys.exit()

    输出结果:

    0 1,1
    1 1,2
    1 2,3
    2 3,5
    3 5,8
    5 8,13
    8 13,21
    13 21,34
    21 34,55
    34 55,89
    55 89,144

    第二种:不使用 yield

    #!/usr/bin/python3
    import sys
    def fibonacci(n,w=0): # 生成器函数 - 斐波那契
     a, b, counter = 0, 1, 0
     while True:
     if (counter > n): 
     return
     #yield a
     a, b = b, a + b
     print('%d,%d' % (a,b))
     counter += 1
    f = fibonacci(10,0) # f 是一个迭代器,由生成器返回生成
    while True:
     try:
     print (next(f), end=" ")
     except :
     sys.exit()

    输出结果:

    1,1
    1,2
    2,3
    3,5
    5,8
    8,13
    13,21
    21,34
    34,55
    55,89
    89,144

    第二种没有yield时,函数只是简单执行,没有返回迭代器f。这里的迭代器可以用生成l列表来理解一下:

    >>> l = [i for i in range(0,15)]
    >>> print(l)
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
    >>> m = (i for i in range(0,15))
    >>> print(m)
    <generator object <genexpr> at 0x104b6f258>
    >>> for g in m:
    ... print(g,end=', ')
    ... 
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
    

    这里的m就像上面的f一样,是迭代器。

    cowpea

    115***[email protected]

    9年前 (2017年07月27日)
  2. #0
    347

    什么情况下需要使用 yield?

    一个函数 f,f 返回一个 list,这个 list 是动态计算出来的(不管是数学上的计算还是逻辑上的读取格式化),并且这个 list 会很大(无论是固定很大还是随着输入参数的增大而增大),这个时候,我们希望每次调用这个函数并使用迭代器进行循环的时候一个一个的得到每个 list 元素而不是直接得到一个完整的 list 来节省内存,这个时候 yield 就很有用。

    具体怎么使用 yield 参考:Python yield 使用浅析

    以斐波那契函数为例,我们一般希望从 n 返回一个 n 个数的 list:

    def fab(max): 
     n, a, b = 0, 0, 1 
     L = [] 
     while n < max: 
     L.append(b) 
     a, b = b, a + b 
     n = n + 1 
     return L

    上面那个 fab 函数从参数 max 返回一个有 max 个元素的 list,当这个 max 很大的时候,会非常的占用内存。

    一般我们使用的时候都是这个样子的,比如:

    f = iter(fab(1000))
    while True:
     try:
     print (next(f), end=" ")
     except StopIteration:
     sys.exit()

    这样我们实际上是先生成了一个 1000 个元素的 list:f,然后我们再去使用这个 f。

    现在,我们换一个方法:

    因为我们实际使用的是 list 的遍历,也就是 list 的迭代器。那么我们可以让这个函数 fab 每次只返回一个迭代器——一个计算结果,而不是一个完整的 list:

    def fab(max): 
     n, a, b = 0, 0, 1 
     while n < max: 
     yield b 
     # print b 
     a, b = b, a + b 
     n = n + 1 

    这样,我们每次调用fab函数,比如这样:

    for x in fab(1000):
     print(x)

    或者 next 函数之类的,实际上的运行方式是每次的调用都在 yield 处中断并返回一个结果,然后再次调用的时候再恢复中断继续运行。

    9年前 (2017年08月01日)
  3. #0

    collector

    120***[email protected]

    197

    对yield的测试结果:

    1. 打个比方的话,yield有点像断点。 加了yield的函数,每次执行到有yield的时候,会返回yield后面的值 并且函数会暂停,直到下次调用或迭代终止;
    2. yield后面可以加多个数值(可以是任意类型),但返回的值是元组类型的。
    def get():
     m = 0
     n = 2
     l = ['s',1,3]
     k = {1:1,2:2}
     p = ('2','s','t')
     while True:
     m += 1
     yield m
     yield m ,n ,l ,k ,p
     
    it = get()
    print(next(it)) #1
    print(next(it)) #(1, 2, ['s', 1, 3], {1: 1, 2: 2}, ('2', 's', 't'))
    print(next(it)) #2
    print(type(next(it))) #<class 'tuple'>

    collector

    120***[email protected]

    8年前 (2018年02月24日)
  4. #0

    怀雨

    522***[email protected]

    56
    def get():
     m = 0
     n = 2
     l = ['s',1,3]
     k = {1:1,2:2}
     p = ('2','s','t')
     while True:
     m += 1
     yield m
     yield m ,n ,l ,k ,p
     
    it = get()
    print(next(it)) #1
    print(next(it)) #(1, 2, ['s', 1, 3], {1: 1, 2: 2}, ('2', 's', 't'))
    print(next(it)) #2
    print(type(next(it))) #<class 'tuple'>

    如果再加一句:

    print(type(next(it))) #<class 'int'> #返回的是整形

    所以返回值的类型,应该是当前调用时,yield 返回值的类型。

    怀雨

    522***[email protected]

    8年前 (2018年05月05日)
  5. #0

    hid4net

    hid***[email protected]

    93

    感谢楼上各位的实例,自己写了一个小例程,便于我这样的新手理解。

    def myYield_1():
     a, i = 'yield', 0
     while True:
     print('before #%d' % i, end=", ")
     yield a, i
     print('after #%d' % i, end=", ")
     i += 1
    def myYield_2():
     a, i = 'yield_a', 0
     b, i = 'yield_b', 0
     while True:
     print('before #%d' % i, end=", ")
     yield a, i
     yield b, i
     print('after #%d' % i, end=", ")
     i += 1
    it1 = iter(myYield_1())
    it2 = iter(myYield_2())
    for i in range(10):
     print("next #%d" % i, end=": ")
     print(next(it1))
    print('\n')
    for i in range(10):
     print("next #%d" % i, end=": ")
     print(next(it2))

    输出是这样的:

    next #0: before #0, ('yield', 0)
    next #1: after #0, before #1, ('yield', 1)
    next #2: after #1, before #2, ('yield', 2)
    next #3: after #2, before #3, ('yield', 3)
    next #4: after #3, before #4, ('yield', 4)
    next #5: after #4, before #5, ('yield', 5)
    next #6: after #5, before #6, ('yield', 6)
    next #7: after #6, before #7, ('yield', 7)
    next #8: after #7, before #8, ('yield', 8)
    next #9: after #8, before #9, ('yield', 9)
    next #0: before #0, ('yield_a', 0)
    next #1: ('yield_b', 0)
    next #2: after #0, before #1, ('yield_a', 1)
    next #3: ('yield_b', 1)
    next #4: after #1, before #2, ('yield_a', 2)
    next #5: ('yield_b', 2)
    next #6: after #2, before #3, ('yield_a', 3)
    next #7: ('yield_b', 3)
    next #8: after #3, before #4, ('yield_a', 4)
    next #9: ('yield_b', 4)

    hid4net

    hid***[email protected]

    8年前 (2018年09月16日)
  6. #0

    前文提到:字符串,列表或元组对象都可用于创建迭代器。

    字符串(Strings):

    普通的旧字符串也是可迭代的。

    for s in "hello":
     print s

    输出结果为:

    h
    e
    l
    l
    o

    列表(Lists):

    这些可能是最明显的迭代。

    for x in [None,3,4.5,"foo",lambda : "moo",object,object()]:
     print "{0} ({1})".format(x,type(x))

    输出结果为:

    None (<type 'NoneType'>)
    3 (<type 'int'>)
    4.5 (<type 'float'>)
    foo (<type 'str'>)
    <function <lambda> at 0x7feec7fa7578> (<type 'function'>)
    <type 'object'> (<type 'type'>)
    <object object at 0x7feec7fcc090> (<type 'object'>)

    元组(Tuples):

    元组在某些基本方面与列表不同,注意到以下示例中的可迭代对象使用圆括号而不是方括号,但输出与上面列表示例的输出相同。

    for x in (None,3,4.5,"foo",lambda : "moo",object,object()):
     print "{0} ({1})".format(x,type(x))

    输出结果为:

    None (<type 'NoneType'>)
    3 (<type 'int'>)
    4.5 (<type 'float'>)
    foo (<type 'str'>)
    <function <lambda> at 0x7feec7fa7578> (<type 'function'>)
    <type 'object'> (<type 'type'>)
    <object object at 0x7feec7fcc090> (<type 'object'>)

    字典(Dictionaries):

    字典是键值对的无序列表。当您使用for循环遍历字典时,您的虚拟变量将使用各种键填充。

    d = {
     'apples' : 'tasty',
     'bananas' : 'the best',
     'brussel sprouts' : 'evil',
     'cauliflower' : 'pretty good'
    }
    for sKey in d:
     print "{0} are {1}".format(sKey,d[sKey])

    输出结果为:

    brussel sprouts are evil
    apples are tasty
    cauliflower are pretty good
    bananas are the best

    也许不是这个顺序,字典是无序的!!!

    8年前 (2019年01月26日)
  7. #0

    wuguandong

    963***[email protected]

    26

    使用自定义迭代器实现斐波那契数列

    class Fibonacci:
     def __init__(self, count):
     self.count = count
     def __iter__(self):
     self.i = 0
     self.a, self.b = 0, 1
     return self
     def __next__(self):
     if self.i < self.count:
     self.i += 1
     a_old = self.a
     self.a, self.b = self.b, self.a + self.b
     return a_old
     else:
     raise StopIteration
    for i in Fibonacci(10):
     print(i, end=" ")

    wuguandong

    963***[email protected]

    7年前 (2019年08月21日)
  8. #0

    闫伟超

    yif***[email protected]

    112

    如教程所说,迭代器和生成器算是 Python 一大特色,其核心是基于迭代器协议来的。

    而平时我们经常使用的 for in 循环体,本质就是迭代器协议的一大应用。

    同时 Python 内置的集合类型(字符、列表、元组、字典)都已经实现了迭代器协议,所以才能使用 for in 语句进行迭代遍历。for in 循环体在遇到 StopIteration 异常时,便终止迭代和遍历。

    再说下可迭代、迭代器、生成器三个概念的联系和区别。

    1、可迭代概念范围最大,生成器和迭代器肯定都可迭代,但可迭代不一定都是迭代器和生成器,比如上面说到的内置集合类数据类型。可以认为,在 Python 中,只要有集合特性的,都可迭代。

    2、迭代器,迭代器特点是,均可以使用 for in 和 next 逐一遍历。

    3、生成器,生成器一定是迭代器,也一定可迭代。

    至于 Python 中为何要引入迭代器和生成器,除了节省内存空间外,也可以显著提升代码运行速度。

    自定义迭代器类示例和说明如下:

    class MyIter():
     def __init__(self):
     #为了示例,用一个简单的列表作为需迭代的数据集合,并且私有化可视情况变为其他类型集合
     self.__list1=[1,2,3,4]
     self.__index=0
     def __iter__(self):
     #该魔法方法,必须返回一个迭代器对象,如果self已经定义了__next__()魔法方法,则只需要返回self即可
     #因为如上面所述,生成器一定是迭代器
     return iter(self.list1) 
     def __next__(self):
     #此处的魔法函数,python会自动记忆每次迭代的位置,无需再使用yield来处理
     #在使用next(obj)时,会自动调用该魔法方法
     res=self.__list1[self.__index]
     self.__index+=1
     return res

    以上为自定义迭代器类的机制。

    下面再示例说明下,如何自定义生成器函数,因为大多数实战场景中,使用生成器函数可能会更多一些:

    def my_gene_func():
     index=0
     li=[1,2,3,4,5]
     yield li[index]
     index+=1

    调用以上函数时,会返回一个生成器对象,然后对该生成器对象,使用 next() 逐一返回:

    gene=my_gene_func()
    next(gene)

    其实核心的概念还是记忆上次迭代的位置,类中直接使用 __next__ 魔法方法实现,函数中使用 yield 实现。且怀疑,类中的 __next__ 魔法方法底层也是使用 yield 来实现的。

    迭代器和生成器具体应用场景,就凡是需要提升运行效率或节约内存资源,且遍历的数据是集合形式的,都可以考虑。

    另外一个小众的使用场景,是变相实现协程的效果,即在同一个线程内,实现不同任务交替执行

    def mytask1():
     print('task1 开始执行')
     '''
     task code
     '''
     yield
    def mytask2():
     print('task2 开始执行')
     '''
     task code
     '''
     yield
    gene1=mytask1()
    gene2=mytask2()
    for i in range(100):
     next(gene1)
     next(gene2)

    闫伟超

    yif***[email protected]

    6年前 (2020年05月14日)
  9. #0

    Python 中 yield 的用法很像 return,都是提供一个返回值,但是 yield 和 return 的最大区别在于,return 一旦返回,则代码段执行结束,但是 yield 在返回值以后,会交出 CUP 的使用权,代码段并没有直接结束,而是在此处中断,当调用 send() 或者 next() 方法之后,yield 可以从之前中断的地方继续执行。

    在一个函数中,使用 yield 关键字,则当前的函数会变成生成器。

    下面生成一个斐波那契数列。

    def fib(n):
     index = 0
     a = 0
     b = 1
     while index < n:
     yield b
     a,b = b, a+b
     index += 1

    生成器对象:

    fib = fib(100)
    print(fib)

    打印出来的结果是一个生成器对象,并没有直接把我们想要的值打印出来。

    <generator object fib at 0x7fef20062ac0>
    仍旧 4年前 (2022年10月10日)
  10. #0

    zbh

    122***[email protected]

    16

    这两段代码是 Python 生成器函数中的重要部分,用于实现斐波那契数列的生成。以下是对这两段代码的详细解释:

    1. yield a: yield 是 Python 中一个非常有用的关键字,它用于定义生成器函数并返回生成器对象。当生成器函数执行到 yield 关键字时,它将将当前函数状态保存为暂停状态,并向调用方返回一个值 a,之后程序流程将被挂起,直到下次通过 next() 函数调用该生成器对象时再恢复执行状态。在斐波那契数列生成器函数中,每次执行到 yield a 时,都会生成当前数列的第一个数字 a 并返回给调用方。
    2. a, b = b, a + b: 这是 Python 中的一种元组赋值语法,可以同时将多个变量赋值为多个值。在斐波那契数列生成器函数中,这行代码的作用是更新相邻两个数字 ab 的值,以便生成下一个斐波那契数。首先,变量 a 被赋值为变量 b 的值,表示将上一个斐波那契数列中的第二个数字赋值为下一个数列的第一个数字;然后,变量 b 被赋值为表达式 a + b 的值,表示将上一个斐波那契数列中的前两个数字相加得到下一个数列中的第二个数字。这样,在每次执行 yield a 之前,都会先更新 ab 的值,从而生成下一个斐波那契数。

    zbh

    122***[email protected]

    3年前 (2023年04月25日)

点我分享笔记

  • 昵称 (必填)
  • 邮箱 (必填)
  • 引用地址

AltStyle によって変換されたページ (->オリジナル) /