Python教程·迭代、可迭代对象、迭代器与生成器详解

iteration(迭代)

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

只要是可迭代对象(Iterable),就可以通过for循环来遍历,这种遍历我们称为迭代。

也就是说所有可作用于for循环的对象都是可迭代对象(Iterable)。

那么,如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断:

>>> from collections import Iterable
>>> isinstance(123,Iterable)            # Integer 不可迭代
False
>>> isinstance(‘abc‘,Iterable)          # String 可迭代
True
>>> isinstance([1,2,3],Iterable)        # List 可迭代
True
>>> isinstance((‘a‘,‘b‘,‘c‘),Iterable)  # Tuple 可迭代
True
>>> isinstance({‘name‘:‘Arno‘,‘Job‘:‘Ops‘},Iterable)    # Dictionary 可迭代
True

dict 迭代说明

默认情况下,dict迭代的是key:

>>> d = {‘Name‘:‘Arno‘,‘Born‘:1993,‘Job‘:‘Ops‘}
>>> for k in d:
...     print(k)
...
Name
Born
Job

如果要迭代value,可以用for value in d.values():

>>> for v in d.values():
...     print(v)
...
Arno
1993
Ops

如果要同时迭代key和value,可以用for k, v in d.items():

>>> for k,v in d.items():
...     print(‘key:‘, k, ‘\t‘, ‘value:‘, v)
...
key: Name    value: Arno
key: Born    value: 1993
key: Job     value: Ops

知识扩展

在Python中,List元素是有索引的,那么如何实现类似Java那样的下标循环?

方法一,通过len()方法取得列表长度,再结合range()方法实现索引下标循环:

>>> L = [‘a‘,‘b‘,‘c‘]
>>> for i in range(len(L)):
...     print(i, L[i])
...
0 a
1 b
2 c

方法二,Python内置的enumerate函数可以把一个list变成 索引-元素 对,这样就可以在for循环中同时迭代索引和元素本身:

>>> for i,v in enumerate(L):
...     print(i, v)
...
0 a
1 b
2 c

iterator(迭代器)

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

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

迭代器有两个基本的方法:

  • iter()
  • next()

可以通过 collections 模块的 Iterator 类型判断一个对象是否是迭代器:

>>> from collections import Iterator
>>> isinstance([1,2,3], Iterator)
False
>>> isinstance({‘Name‘:‘Arno‘,‘Born‘:1993,‘Job‘:‘Ops‘}, Iterator)
False
>>> isinstance(‘abc‘, Iterator)
False
>>> isinstance(iter([1,2,3]), Iterator)             # iter()创建迭代器对象
True
>>> isinstance((x for x in range(10)), Iterator)    # 生成器
True

可以看出,生成器(generator)都是迭代器(Iterator)对象,但String、List、Tuple、Dict虽然是可迭代对象(Iterable),却不是迭代器(Iterator)。

当然,String、List、Tuple、Dict等可迭代对象都可用于创建迭代器:

>>> L = [1,2,3]
>>> it = iter(L)
>>> print(next(it))
1
>>> print(next(it))
2
>>> print(next(it))
3
>>> print(next(it))     # 没有值可返回时,抛异常 StopIteration
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> 

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

>>> L = [1,2,3]
>>> it = iter(L)
>>> for x in it:
...     print(x, end=" ")
...
1 2 3 

也可以使用 next() 函数:

>>> import sys
>>> L = [1,2,3]
>>> it = iter(L)
>>> while True:
...     try:
...         print(next(it))
...     except StopIteration:
...         sys.exit()
...
1
2
3

generator(生成器)

创建生成器的方法:

  • 使用了 yield 语句的函数
    Generator 是一个用于创建迭代器的简单而强大的工具。 它们的写法类似标准的函数,但当它们要返回数据时会使用 yield 语句。 每次对生成器调用 next() 时,它会从上次离开位置恢复执行(它会记住上次执行语句时的所有数据值)。
  • 使用生成器表达式,就是把一个 列表生成式 的[]改成()
    某些简单的生成器可以写成简洁的表达式代码,所用语法类似列表推导式,将外层为圆括号而非方括号。 这种表达式被设计用于生成器将立即被外层函数所使用的情况。 生成器表达式相比完整的生成器更紧凑但较不灵活,相比等效的列表推导式则更为节省内存。

yield 函数生成器

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

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

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回yield的值。并在下一次执行 next()方法时从当前位置继续运行。

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

import sys

def fibonacci(n): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n):
            return
        yield a
        a, b = b, a + b
        counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成

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

列表生成式

列表生成式(List Comprehensions)也叫列表推导式,提供了一个更简单的创建列表的方法。

常见的用法:

  • 是把某种操作应用于序列或可迭代对象的每个元素上,然后使用其结果来创建列表;
  • 或者通过满足某些特定条件元素来创建子序列;

例如,创建一个平方列表,像这样

>>> squares = []
>>> for x in range(10):
...     squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

可以改为

>>> list(map(lambda x: x**2, range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

等价于

# 列表推导式,更加简洁易读
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

增加特定条件

>>> [x**2 for x in range(10) if x % 2 != 0]
[1, 9, 25, 49, 81]

创建为生成器

>>> (x**2 for x in range(10) if x % 2 != 0)
<generator object <genexpr> at 0x7f076f06e990>

知识扩展

lambda 表达式

lambda 表达式(有时称为 lambda 构型)被用于创建匿名函数。

表达式 lambda parameters: expression 会产生一个函数对象 。 该未命名对象的行为类似于用以下方式定义的函数:

def <lambda>(parameters):
    return expression

注意:通过 lambda 表达式创建的函数不能包含语句或标注。

map() 高阶函数

接收两个参数,一个是函数,一个是可迭代对象(Iterable),map将传入的函数依次作用到序列的每个元素,并把结果作为新的iterator(迭代器)返回。

总结

  • 迭代(iteration)是访问集合元素的一种方式;
  • 迭代器(iterator)对象一定是可迭代对象,反之则不一定;
  • 可迭代对象(Iterable)不一定是迭代器;
    例如list、dict、str等集合数据类型是可迭代对象,但不是迭代器,但是它们可以通过iter()函数生成一个迭代器对象。
  • 生成器(generator)对象既是可迭代对象也是迭代器;

遍历方式

  • 迭代器、生成器和可迭代对象都可以用for循环去迭代
  • 生成器和迭代器还可以被next()方函数调用并返回下一个值

原文地址:https://blog.51cto.com/opsarno/2364308

时间: 2024-11-07 18:05:00

Python教程·迭代、可迭代对象、迭代器与生成器详解的相关文章

[js高手之路] es6系列教程 - 迭代器与生成器详解

什么是迭代器? 迭代器是一种特殊对象,这种对象具有以下特点: 1,所有对象都有一个next方法 2,每次调用next方法,都会返回一个对象,该对象包含两个属性,一个是value, 表示下一个将要返回的值.另一个是done,他是一个布尔值,用来表示该迭代器是否还有数据可以返回. 3,迭代器还会保存一个内部指针指向当前集合中的值 设计模式中有个迭代模式,跟迭代器是差不多的,我之前有写过2篇文章关于迭代模式: [js高手之路] 设计模式系列课程 - 迭代器(1) [js高手之路] 设计模式系列课程 -

Python教程:操作数据库,MySql的安装详解

各位志同道合的同仁请点击上方关注 本教程是基于Python语言的深入学习.本次主要介绍MySql数据库软件的安装.不限制语言语法,对MySql数据库安装有疑惑的各位同仁都可以查看一下. 如想查看学习Python相关文章,请移步:Python开发实战系列教程-链接汇总,持续更新. 数据库的应用在软件开发领域是重重之重.大量数据和配置被保存在数据库中以被使用.如果想开发一套软件系统与数据库是分不开的.发展到现在,各类数据库应需求而生:关系型与非关系型.单机与分布式.文件型内存型等等. 对于关系型数据

Python 迭代对象、迭代器、生成器详解

在了解Python的数据结构时,容器(container).可迭代对象(iterable).迭代器(iterator).生成器(generator).列表/集合/字典推导式(list,set,dict comprehension)众多概念参杂在一起,难免让初学者一头雾水,本文将一一为大家进行介绍,希望对大家学习python有所帮助. 容器(container) 容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用 in ,  not in 关键字判断元素是否包含在容器

python 迭代器与生成器 详解

在python中,我们经常使用for循环来遍历各种集合,例如最常用的有list,dict等等,这些集合都是可迭代对象.我们先来了解一下python中的迭代器(Iterator). 一.迭代器 顾名思义,迭代器,自然就是用来做迭代用的(好像是废话).以list为例,我们用list,最多的情况就是用来做循环了(循环就是迭代嘛) >>> list = [1,2,3] >>> dir(list) ['__add__', '__class__', '__contains__',

python学习笔记8--面向对象--属性和方法详解

属性: 公有属性  (属于类,每个类一份) 普通属性  (属于对象,每个对象一份) 私有属性    (属于对象,跟普通属性相似,只是不能通过对象直接访问) 方法:(按作用) 构造方法 析构函数 方法:(按类型) 普通方法 私有方法(方法前面加两个下划线) 静态方法 类方法 属性方法 静态方法 @staticmethod静态方法,通过类直接调用,不需要创建对象,不会隐式传递self 类方法 @classmethod类方法,方法中的self是类本身,调用方法时传的值也必须是类的公有属性,就是说类方法

Swift研究之编程高级教程(二)属性,存储属性详解

 属性 属性是依赖于某个特定的类.结构体或者枚举类型的值.Swift有两种属性:存储类型和计算类型.其中存储类型可以作为实例的一部分存放变量或者常量的值,而计算类型的属性值是通过运算的来的.计算类型的属性可以在类.结构体和枚举类型中出现,但存储类型只可能出现在类和结构体类型中. 属性一般依赖于一个特定类型的实例,但是也可以依赖于类本身.依赖于类型本身的属性称为类型属性. 可以定义属性观察者来监督属性值的改变,从而作出响应.对集合不明白的看集合类型-数组详解 存储属性 常量属性let的值在初始

JavaScript原生对象属性和方法详解——Array对象 转载

length 设置或返回 数组中元素的数目. 注意:设置 length 属性可改变数组的大小.如果设置的值比其当前值小,数组将被截断,其尾部的元素将丢失.如果设置的值比它的当前值大,数组将增大,新的元素被添加到数组的尾部,它们的值为 undefined.所以length不一定代表数组的元素个数. var arr = new Array(3) arr[0] = "John" arr[1] = "Andy" arr[2] = "Wendy" cons

js对象浅拷贝和深拷贝详解

js对象浅拷贝和深拷贝详解 作者:i10630226 字体:[增加 减小] 类型:转载 时间:2016-09-05我要评论 这篇文章主要为大家详细介绍了JavaScript对象的浅拷贝和深拷贝代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 本文为大家分享了JavaScript对象的浅拷贝和深拷贝代码,供大家参考,具体内容如下 1.浅拷贝 拷贝就是把父对像的属性,全部拷贝给子对象. 下面这个函数,就是在做拷贝: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 var

Dream------scala--类的属性和对象私有字段实战详解

Scala类的属性和对象私有字段实战详解 一.类的属性 scala类的属性跟java有比较大的不同,需要注意的是对象的私有(private)字段 1.私有字段:字段必须初始化(当然即使不是私有字段也要赋值) 2.属性默认是public级别的,而且无法用public修饰. 3.可以有很多类,并且默认是public级别(如果声明的时候加上会报错,不知为何) 4.如果属性是public的,会默认生成类属性的getter和setter方法,无需显示的提供getter,setter方法 5.私有字段(用p