生成器和迭代器

介绍

生成器和迭代器_第1张图片

什么是迭代器?迭代器是可以像我们在 for 循环中那样迭代的对象。我们也可以说迭代器是一个对象,它一次返回一个元素。也就是说,在我们明确要求他们的下一个项目之前,他们不会做任何工作。它们的工作原理在计算机科学中称为惰性求值。惰性求值是一种求值策略,它将表达式的求值延迟到真正需要它的值。由于 Python 迭代器的惰性,它们是处理无穷大的好方法,即可以永远迭代的可迭代对象。您几乎找不到不与迭代器配合使用的 Python 程序。

迭代器是 Python 的一个基本概念。您已经在第一个 Python 程序中了解到可以迭代容器对象,例如列表和字符串。为此,Python 创建了列表或字符串的迭代器版本。在这种情况下,迭代器可以被看作是一个指向容器的指针,它使我们能够迭代这个容器的所有元素。迭代器是一种抽象,它使程序员能够访问可迭代对象(集合、字符串、列表等)的所有元素,而无需深入了解该对象的数据结构。

生成器是一种特殊的函数,它使我们能够实现或生成迭代器。

大多数情况下,迭代器是隐式使用的,就像在 Python 的 for 循环中一样。我们在以下示例中演示了这一点。我们正在迭代一个列表,但您不要误会:列表不是迭代器,但它可以像迭代器一样使用:

城市 =  [ “巴黎” “柏林” “汉堡” “法兰克福” “伦敦” “维也纳” “阿姆斯特丹” “海牙” ]
 位置  城市:
    打印“位置:”  + 位置)

输出:

地点:巴黎
地点:柏林
地点:汉堡
地点:法兰克福
地点:伦敦
地点:维也纳
地点:阿姆斯特丹
地点:海牙

执行 for 循环时到底发生了什么?函数'iter' 应用于'in' 关键字之后的对象,例如for i in o:。可能有两种情况: o 是可迭代的或不可迭代的。如果 o 不可迭代,则会引发异常,表示对象的类型不可迭代。另一方面,如果 o 是可迭代的,则调用 iter(o) 将返回一个迭代器,让我们称其为 iterator_obj for 循环使用此迭代器通过使用 next 方法迭代对象 o。当 next(iterator_obj) 耗尽时 for 循环停止,这意味着它返回一个 StopIteration 异常。我们在以下代码示例中演示了这种行为:

专业知识 =  [ “Python 初学者” “Python 中级” “Python 精通” “Python 高级” ]
专业知识 迭代器=  iter (专业知识)
打印“第一次调用“下一步”:“ 下一步(专业知识迭代器))
打印“第二次调用‘next’:” next ( experts_iterator ))

输出:

第一次调用“next”:Python 初学者
第二次调用“next”:Python 中级

我们本可以再调用next两次,但在这之后我们会得到一个 StopIteration 异常。

我们可以在 while 循环中模拟 for 循环的这种迭代行为:您可能已经注意到我们的程序中缺少一些东西:我们必须捕获“停止迭代”异常:

other_cities  =  [ "Strasbourg" ,  "Freiburg" ,  "Stuttgart" ,  
                "Vienna / Wien" ,  "Hannover" ,  "Berlin" ,  
                "Zurich" ] 
city_iterator  =  iter ( other_cities )
 city_iterator : 
    try : 
        city  =  next ( city_iterator )
        打印(城市)
    除了 StopIteration break

输出:

斯特拉斯堡
弗莱堡
斯图加特
维也纳/维也纳
汉诺威
柏林
苏黎世

Python 标准库的顺序基类型以及大多数类都支持迭代。字典数据类型 dict 也支持迭代器。在这种情况下,迭代会遍历字典的键:

资本 =  {  
    “法国” “巴黎” “荷兰” “阿姆斯特丹” “德” “柏林” “瑞士” “伯尔尼” “奥地利” “维也纳” }
 国家  首都:
     印刷““  + 国家 +  ”的 首都是“ + 首都[国家])

输出:

法国的首都是巴黎
荷兰的首都是阿姆斯特丹
德国的首都是柏林
瑞士的首都是伯尔尼
奥地利的首都是维也纳

题外话:从我们的例子中了解到,荷兰的首都不是海牙(海牙)而是阿姆斯特丹,有些读者可能会感到困惑。根据宪法,阿姆斯特丹是荷兰的首都,尽管荷兰议会和荷兰政府以及最高法院和国务委员会都位于海牙。

将迭代器实现为类

在 Python 中创建迭代器的一种方法是定义一个实现方法__init____next__. 我们通过实现一个类循环来展示这一点,该循环可用于永远循环遍历一个可迭代对象。换句话说,这个类的一个实例返回一个可迭代的元素,直到它用完为止。然后它无限期地重复该序列。

class  Cycle ( object ): 
    def  __init__ ( self ,  iterable ): 
        self 可迭代 = 可迭代
        self iter_obj  =  iter ( iterable ) 
    def  __iter__ ( self ): 
        return  self 
    def  __next__ ( self ): 
        while  True : 
            try : 
                next_obj  =  next ( self . iter_obj ) 
                return next_obj
            除了 StopIteration : 
                self iter_obj  =  ITER (自我可迭代)
X  = 周期(“ABC”  范围(10 ):
    打印下一个(X ), 结束= “” 

输出:

a、b、c、a、b、c、a、b、c、a、 

尽管创建迭代器的面向对象方法可能非常有趣,但这不是 Pythonic 方法。

在 Python 中创建迭代器的常用且最简单的方法是使用生成器函数。您将在下一章中了解这一点。

发电机

从表面上看,Python 中的生成器看起来像函数,但在语法和语义上都存在差异。一个显着特征是产量声明。yield 语句将函数转换为生成器。生成器是一个返回生成器对象的函数。这个生成器对象可以看作是一个函数,它产生一系列结果而不是单个对象。这个值序列是通过迭代它产生的,例如使用 for 循环。可以迭代的值是通过使用 yield 语句创建的。yield 语句创建的值是 yield 关键字之后的值。当到达 yield 语句时,代码的执行停止。将返回 yield 背后的值。生成器的执行现在被中断。一旦在生成器对象上再次调用“next”,生成器函数将在最后一次调用的代码中的 yield 语句之后立即恢复执行。执行将在最后一次让步之后生成器离开的状态继续执行。换句话说,所有局部变量仍然存在,因为它们在调用之间自动保存。这是与函数的根本区别:函数总是在函数体的开头开始执行,而不管它们在之前的调用中离开了哪里。它们没有任何静态或持久值。生成器的代码中可能有多个 yield 语句,或者 yield 语句可能位于循环体内。如果生成器的代码中有 return 语句,当 Python 解释器执行此代码时,执行将停止并出现 StopIteration 异常错误。“发电机”这个词

可以用生成器完成的所有事情也可以用基于类的迭代器来实现。然而,生成器的关键优势在于自动创建方法__iter__() 和 next()。生成器提供了一种非常简洁的方式来生成巨大甚至无限的数据。

下面是一个简单的生成器示例,它能够生成各种城市名称。

可以用这个生成器创建一个生成器对象,它一个接一个地生成所有城市名称。

def  city_generator (): 
    yield ( "Hamburg" ) 
    yield ( "Konstanz" ) 
    yield ( "Berlin" ) 
    yield ( "Zurich" ) 
    yield ( "Schaffhausen" ) 
    yield ( "Stuttgart" )  

我们通过调用 city_generator() 创建了一个迭代器:

city  =  city_generator ()
打印下一个(城市))

输出:

汉堡
打印下一个(城市))

输出:

康斯坦茨
打印下一个(城市))

输出:

柏林
打印下一个(城市))

输出:

苏黎世
打印下一个(城市))

输出:

沙夫豪森
打印下一个(城市))

输出:

斯图加特
打印下一个(城市))

输出:

-------------------------------------------------- ------------------------- 
StopIteration                              Traceback (最近一次调用最后一次)
  in  
---- > 1打印( next ( city ) ) 
StopIteration :

如我们所见,我们city在交互式 shell 中生成了一个迭代器。每次调用该方法都会next(city)返回另一个城市。在最后一个城市,即斯图加特创建完成后,另一个调用next(city)抛出异常,说迭代已经停止,即StopIteration. “我们可以向迭代器发送重置吗?” 是一个常见问题,因此它可以重新开始迭代。没有重置,但可以创建另一个生成器。这可以通过例如再次使用语句“city = city_generator()”来完成。虽然乍一看,yield 语句看起来像函数的 return 语句,但我们可以在这个例子中看到有很大的不同。如果我们有一个 return 语句而不是前一个例子中的 yield,它就是一个函数。但此函数将始终返回第一个城市“汉堡”,而不会返回任何其他城市,即“康斯坦茨”、“柏林”、“苏黎世”、“沙夫豪森”和“斯图加特”

操作方法

正如我们在本章的介绍中所阐述的,生成器提供了一种生成迭代器的舒适方法,这就是它们被称为生成器的原因。

生成器和迭代器_第2张图片

 

工作方法:

  • 生成器就像函数一样被调用。它的返回值是一个迭代器,即生成器对象。生成器的代码不会在这个阶段执行。
  • 迭代器可以通过调用 next 方法来使用。第一次执行像函数一样开始,即迭代器主体内的第一行代码。代码会一直执行,直到到达 yield 语句。
  • yield返回表达式的值,它跟在关键字 yield 之后。这就像一个函数,但是 Python 会跟踪这个 yield 的位置,并且会存储局部变量的状态以备下次调用。在下一次调用时,继续执行 yield 语句之后的语句,并且变量的值与它们在前一次调用中的值相同。
  • 如果生成器主体已完全运行或程序流遇到没有值的返回语句,则迭代器已完成。

我们将在以下示例中说明这种行为。生成器计数创建一个迭代器,它通过从起始值 'firstval' 开始计数并使用 'step' 作为计数的增量来创建一系列值:

def  count ( firstval = 0 ,  step = 1 ): 
    x  =  firstval 
    while  True : 
        <

你可能感兴趣的:(计算机,python,分类,开发语言,数据挖掘)