Python 进阶_迭代器 & 列表解析

简介: 目录目录迭代器iter 内建的迭代器生成函数迭代器在 for 循环中迭代器与字典迭代器与文件创建迭代器对象创建迭代对象并实现委托迭代迭代器的多次迭代列表解析列表解析的样例列表解析和迭代器迭代器迭代器是一个含有 next() 方法的对象,让我们可以迭代不是序列数据类型但表现出序列行为的对象,所以可以说迭代器为类序列对象提供了一个类序列的接口(只要是实现了 __iter__() 方法的对象,就可以使用迭代器来进行访问)。

目录

迭代器

迭代器是一个含有 next() 方法的对象,让我们可以迭代不是序列数据类型但表现出序列行为的对象,所以可以说迭代器为类序列对象提供了一个类序列的接口(只要是实现了 __iter__() 方法的对象,就可以使用迭代器来进行访问)。迭代器从对象的第一个元素开始访问,直到所有的元素被遍历后结束。对于无法通过索引计数来随机访问元素的数据结构(EG. set)而言,迭代器是唯一的访问其自身元素的方式。

NOTE1: 但迭代器是不支持索引计数的,所以迭代器不能回退,只能往前进行迭代。

NOTE2: 迭代器也不是线程安全的,在多线程环境中对可变对象使用迭代器是一个危险的操作。所以一般情况下应该坚持对不可变对象实现迭代器。

NOTE3: 迭代器对象不支持被多次迭代

In [19]: a = ListIter([1,2,3,4,5])

In [20]: [i for i in a]
Out[20]: [1, 2, 3, 4, 5]

In [21]: [i for i in a]
Out[21]: []

In [22]:

iter() :内建的迭代器生成函数

iter(…)
iter(collection) -> iterator
iter(callable, sentinel) -> iterator

Get an iterator from an object.  In the first form, the argument must
supply its own iterator, or be a sequence.
In the second form, the callable is called until it returns the sentinel.

1. 如果传递了一个序列(sequence)实参,迭代器会从索引 0 一直迭代至结束。
2. 如果传递了两个实参 EG. iter(func, sentinel),迭代器会重复的调用 func 直到迭代器的下一个值为 sentinel 。

EXAMPLE 1

In [44]: aList = ['jmilkfan', 'fanguiju', 'chocolate']

In [45]: aIter = iter(aList)

In [46]: aIter.next()
Out[46]: 'jmilkfan'

In [47]: aIter.next()
Out[47]: 'fanguiju'

In [48]: next(aIter)
Out[48]: 'chocolate'

In [49]: aIter.next()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-49-5ab62b0e2847> in <module>()
----> 1 aIter.next()

StopIteration:

迭代器通过其内建的 iter.next() 方法,或通过 Python 内建的 next() 来迭代下一个元素,直到最后触发 StopIteration 异常后表示迭代结束。

EXAMPLE 2: 捕获异常

In [56]: aList = ['jmilkfan', 'fanguiju', 'chocolate']

In [57]: aIter = iter(aList)

In [58]: while True:
    ...:     try:
    ...:         print aIter.next()
    ...:     except StopIteration:
    ...:         print 'Done'
    ...:         break
    ...:
jmilkfan
fanguiju
chocolate
Done

迭代器在 for 循环中

EXAMPLE 3: 对 EXAMPLE 2 的改进

In [59]:  aList = ['jmilkfan', 'fanguiju', 'chocolate']

In [60]:  aIter = iter(aList)

In [61]: for x in aIter:
    ...:     print x
    ...:
jmilkfan
fanguiju
chocolate

Python 在 for 循环的语法糖中,让 for 循环能够自动的调用迭代器的 next() 方法以及捕获 StopIteration 异常。

迭代器与字典

字典是一个可迭代对象,其迭代器会变量它的 key, 所以我们可以应用这个特性将语句 for eachKey in myDict.keys() 改进为 for eachKey in myDict
EXAMPLE 4:

In [62]: aDict = {'name':'jmilkfan', 'sex':'man'}

In [69]: for x in aDict:
    ...:     print ''.join([x,': ',aDict[x]])
    ...:
name: jmilkfan
sex: man

迭代器与文件

文件也是一个可迭代对象,迭代器会自动的调用文件对象的 readline() 方法,所以可以将语句 for eachLine in myFile.readlines() 修改为 for eachLine in myFile
EXAMPLE 5:

myFile = open('FILENAME')

for eachLine in myFile:
    print eachLine

myFile.close()

创建迭代器对象

EXAMPLE 6: 一个斐波那契数列

class Fab(object): 
   def __init__(self, max): 
       self.max = max 
       self.n, self.a, self.b = 0, 0, 1 

   def __iter__(self): 
       return self 

   def next(self): 
       if self.n < self.max: 
           r = self.b 
           self.a, self.b = self.b, self.a + self.b 
           self.n = self.n + 1 
           return r 
       raise StopIteration()

if __name__ == '__main__':
    fab = Fab(5)
    print fab
    for x in fab:
        print x

Output:

In [79]: run demo_1.py
<__main__.Fab object at 0x00000000047CDE80>
1
1
2
3
5

将实例化语句 fab = Fab(5) 修改成 fab = Fab(100) 后执行,再看看 Output:

1
.
.
.
354224848179261915075

NOTE: 这一类的应用场景会对内存造成非常大的负担,建议使用迭代器来减少内存的压力。

EXAMPLE 6 中的 __iter__() 方法 return 了自己,所以迭代的对象就是自身。除此之外,我们还可以实现 委托迭代

创建迭代对象并实现委托迭代

委托迭代:就是将迭代请求委托到迭代对象内部持有的容器对象上。它能让自己创建的新容器能够完成迭代操作。
EXAMPLE 7

class Node:                   
    def __init__(self, value):
        self._value = value
        self._children = []            # 迭代对象所持有的容器对象

    def __repr__(self):
        return 'Node({!r})'.format(self._value)

    def add_child(self, node):
        self._children.append(node)

    def __iter__(self):
        return iter(self._children)      # 将迭代请求转发给迭代对象内部所持有的容器对象

if __name__ == '__main__':
    root = Node(0)
    child1 = Node(1)
    child2 = Node(2)
    root.add_child(child1)
    root.add_child(child2)
    for ch in root:   # 调用 Node:__iter__()
        print(ch)     # 调用 Node:__repr__()

Output:

Node(1)
Node(2)

EXAMPLE 7 是一个树结构,执行自身(root),返回子节点(Node(1)、Node(2)) 。这个例子,当我们 for 循环遍历迭代器对象 root 时,实际上是迭代了 self._children = [Node(1), Node(2)],这就是迭代委托。

迭代器的多次迭代

在上文写到,迭代器不支持被多次迭代,这样实在不能说是灵活。为了解决这一个问题,引入了可迭代对象(iterables)迭代器对象(iterator)两个不同的概念。

  • 迭代器对象__iter__() 返回的是迭代器对象自身。
  • 可迭代对象__iter__() 返回了一个迭代器对象。

上述的 委托迭代 就是一个返回一个迭代器对象的例子,所以 EXAMPLE 7 是一个 可迭代对象,他能够被多次迭代。

In [1]: run demo_1.py
Node(1)
Node(2)

In [2]: run demo_1.py
Node(1)
Node(2)

列表解析

是一个非常有用、简单且灵活的工具,让我们能够动态的创建列表类型对象。
语法

[expr for iter_variable in iterable]

EXAMPLE 1

In [18]: [x**2 for x in range(10)]
Out[18]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

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

上面两条语句的效果是一样的,但列表解析的方法仅调用一次 range(10), 而第二条则调用了 map()/lambda/range(10),这说明列表解析可以替代 map() 以及 lambda ,以此来获取更高的效率

列表解析的样例

  • 嵌套 for 循环实现的矩阵
In [81]: [(x+1, y+1) for x in range(3) for y in range(5)]
Out[81]:
[(1, 1),
 (1, 2),
 (1, 3),
 (1, 4),
 (1, 5),
 (2, 1),
 (2, 2),
 (2, 3),
 (2, 4),
 (2, 5),
 (3, 1),
 (3, 2),
 (3, 3),
 (3, 4),
 (3, 5)]
  • 统计文件单词数
f = opem('FILENAME', 'r')
len([word for line in f for word in line.split()])
  • 求素数
[x for x in range(2,100) if not [y for y in range(2,int(x/2+1)) if x % y == 0]]
  • 嵌套列表降维
In [143]: nestLi = [[1,2,3],[4,5,6],[7,8,9]]

In [144]: newLi = [x for para in nestLi for x in para]

In [145]: newLi
Out[145]: [1, 2, 3, 4, 5, 6, 7, 8, 9]

列表解析和迭代器

因为 for 循环的关系,所以从上面的例子可以看出列表解析和迭代器之间的关系非常紧密。深入的理解两者,对提高 Python 程序的效率有非常大的帮助。迭代是 Python 一个非常重要的思想和特性。

相关文章
|
23天前
|
开发者 Python 容器
深入理解Python迭代器:迭代机制的核心与应用
本文介绍了Python迭代器的核心概念、工作原理和应用场景。迭代器是遍历容器类型数据结构(如列表、元组、字典和集合)的对象,遵循迭代器协议,具有记忆遍历位置和一次性特点。通过实现迭代器协议,开发者能为自定义类型定义迭代行为,实现高效处理大量数据和与其他迭代工具协同工作。迭代器与可迭代对象的区别在于,可迭代对象实现`__iter__()`方法,返回迭代器,而迭代器实现`__next__()`方法,用于逐个访问元素。理解并运用迭代器能提升Python代码的性能和可读性。
|
18天前
|
存储 缓存 算法
Python中collections模块的deque双端队列:深入解析与应用
在Python的`collections`模块中,`deque`(双端队列)是一个线程安全、快速添加和删除元素的双端队列数据类型。它支持从队列的两端添加和弹出元素,提供了比列表更高的效率,特别是在处理大型数据集时。本文将详细解析`deque`的原理、使用方法以及它在各种场景中的应用。
|
1天前
|
调度 Python
Python多线程、多进程与协程面试题解析
【4月更文挑战第14天】Python并发编程涉及多线程、多进程和协程。面试中,对这些概念的理解和应用是评估候选人的重要标准。本文介绍了它们的基础知识、常见问题和应对策略。多线程在同一进程中并发执行,多进程通过进程间通信实现并发,协程则使用`asyncio`进行轻量级线程控制。面试常遇到的问题包括并发并行混淆、GIL影响多线程性能、进程间通信不当和协程异步IO理解不清。要掌握并发模型,需明确其适用场景,理解GIL、进程间通信和协程调度机制。
17 0
|
1天前
|
API Python
Python模块化编程:面试题深度解析
【4月更文挑战第14天】了解Python模块化编程对于构建大型项目至关重要,它涉及代码组织、复用和维护。本文深入探讨了模块、包、导入机制、命名空间和作用域等基础概念,并列举了面试中常见的模块导入混乱、不适当星号导入等问题,强调了避免循环依赖、合理使用`__init__.py`以及理解模块作用域的重要性。掌握这些知识将有助于在面试中自信应对模块化编程的相关挑战。
17 0
|
3天前
|
Python
python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)(上)
python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)(上)
25 0
|
3天前
|
大数据 数据处理 开发者
深入理解Python中的迭代器和生成器
Python中的迭代器和生成器是实现高效循环和处理大型数据集的重要工具。本文将深入探讨迭代器和生成器的概念、原理以及在实际开发中的应用场景,帮助读者更好地理解和利用这些强大的工具。
|
5天前
|
SQL API 数据库
Python中的SQLAlchemy框架:深度解析与实战应用
【4月更文挑战第13天】在Python的众多ORM(对象关系映射)框架中,SQLAlchemy以其功能强大、灵活性和易扩展性脱颖而出,成为许多开发者首选的数据库操作工具。本文将深入探讨SQLAlchemy的核心概念、功能特点以及实战应用,帮助读者更好地理解和使用这一框架。
|
16天前
|
人工智能 机器人 测试技术
【Python】Python迭代器与生成器的区别(详细讲解)
【Python】Python迭代器与生成器的区别(详细讲解)
【Python】Python迭代器与生成器的区别(详细讲解)
|
18天前
|
数据采集 数据挖掘 Python
Python中collections模块的Counter计数器:深入解析与应用
在Python的`collections`模块中,`Counter`是一个强大且实用的工具,它主要用于计数可哈希对象。无论是统计单词出现的频率,还是分析数据集中元素的分布情况,`Counter`都能提供快速且直观的结果。本文将深入解析`Counter`计数器的原理、用法以及它在实际应用中的价值。
|
25天前
|
安全 Python
Python封装:深入解析与应用
封装是Python面向对象编程的关键,通过隐藏对象属性和实现细节,提供公共访问方式,确保代码安全和可维护。实现封装主要通过类和对象,使用私有属性(__前缀)及访问器/修改器方法。封装能隐藏内部状态、统一接口、复用代码和增强扩展性。示例展示了如何用私有属性和访问器方法控制属性访问。掌握封装有助于编写高效、灵活的代码。

热门文章

最新文章

推荐镜像

更多