Python迭代对象、迭代器、生成器学习理解笔记
理解Python数据结构时,容器(containers)、可迭代对象(iterables)、迭代器(iterators)、生成器(generators)、列表/集合/的很多字典概念理解(列表、集合、听写理解)混在一起,这肯定会让初学者感到困惑。我将用这篇文章来尝试解释这些概念以及它们之间的关系。
Container(容器)
容器是一种将多个元素一起管理的数据结构。容器中的元素可以一次迭代获取一个。您可以使用 in
、not in
关键字来判断元素是否在容器内部。通常这种类型的数据结构将所有元素存储在内存中(也有一些特殊情况并非所有元素都存储在内存中,例如迭代器和生成器对象)。在 Python 中,常见的容器对象有:
- list 、 deque、....
- set、frozensets、....
- dict、defaultdict、OrderedDict、Counter、....
- tuple、 namedtuple, ...
- str
容器比较很容易理解,因为你可以想到一个盒子,一个房子,或者一个壁橱,任何东西都可以被填充。从技术角度来看,当它可以用来询问某个元素是否存在时,那么该对象就可以被认为是一个容器。例如,列表、集合和元组都是容器对象:
>>> assert 1 in [1, 2, 3] # lists
>>> assert 4 not in [1, 2, 3]
>>> assert 1 in {1, 2, 3} # sets
>>> assert 4 not in {1, 2, 3}
>>> assert 1 in (1, 2, 3) # tuples
>>> assert 4 not in (1, 2, 3)
询问是否包含元素 在 dict 中使用 dict 键:
>>> d = {1: 'foo', 2: 'bar', 3: 'qux'}
>>> assert 1 in d
>>> assert 'foo' not in d # 'foo' 不是dict中的元素
询问子字符串是否在字符串中:
>>> s = 'foobar'
>>> assert 'b' in s
>>> assert 'x' not in s
>>> assert 'foo' in s
虽然许多容器提供了多种方法检索 person 中的每个元素,这不是容器提供的功能。 ,但是可迭代对象为这种能力提供了一个容器。当然,并不是所有的容器都可以重复,比如:布隆过滤器,虽然可以利用布隆过滤器来检测容器中有元素,但是无法从容器中获取每个值,因为布隆过滤器并不能根本不将元素存储在容器中,而是通过哈希函数将它们映射到 Value 并将其存储在数组中。
可迭代对象(iterable)
正如我所说,许多容器都是可迭代对象。此外,还有其他对象也是可迭代对象,例如打开的文件、套接字等。任何能够产生 Iterator 的对象都可以称为可迭代对象。听起来可能有点令人困惑。没问题。我们先看一下例子:
>>> x = [1, 2, 3]
>>> y = iter(x)
>>> z = iter(x)
>>> next(y)
1
>>> next(y)
2
>>> next(z)
1
>>> type(x)
<class 'list'>
>>> type(y)
<class 'list_iterator'>
这里x
是一个可迭代对象。可迭代对象(Iterable object),可迭代对象是容器之类的俗称,并不指代具体的数据类型。 List是一个可迭代对象,dict是一个可迭代对象,set也是一个可迭代对象。 y
和 z
是两个独立的迭代器。迭代器有内部状态。该状态用于记录当前迭代的位置,以便在下一次迭代时检索它。正确的元素。迭代器有特定的迭代器类型,例如 list_iterator
、set_iterator
。可迭代对象实现方法 __iter__
,该方法返回一个迭代器对象。
运行代码时:
x = [1, 2, 3]
for elem in x:
...
正确的执行是:
反编译这段代码,可以看到解释器显式调用了指令“
FOR_ITER
是调用next()
,但是你不能直接从exit指令旁边的元素看到它,因为它是通过口译员。 >>> import dis
>>> x = [1, 2, 3]
>>> dis.dis('for _ in x: pass')
1 0 SETUP_LOOP 14 (to 17)
3 LOAD_NAME 0 (x)
6 GET_ITER
>> 7 FOR_ITER 6 (to 16)
10 STORE_NAME 1 (_)
13 JUMP_ABSOLUTE 7
>> 16 POP_BLOCK
>> 17 LOAD_CONST 0 (None)
20 RETURN_VALUE
Iterator(迭代器)
那么什么是迭代器呢?这是一个有状态对象,当您调用 所以,迭代器是一个实现工厂模式的对象。每次您请求下一个值时,都会返回您。迭代器的例子有很多。例如,函数 创建无限序列: 从完整序列创建无限序列: 从无限序列创建完整序列: 为了感受执行过程,我们配置一个 Iterator,将以斐波那契数列为例: Fib 是一个可迭代对象(因为它实现了方法 交互器就像懒惰的工厂。直到有人需要它并返回它时,它才会返回值。当没有被调用时,它会处于休眠状态,等待下一次调用。 生成器是Python语言最有趣的功能之一。生成器实际上是特殊的迭代器,但是这个迭代器更加优雅。不需要像上面的类那样写方法 生成器是 Python 中非常强大的编程结构。可以用更少的中间变量编写流代码。此外,与其他容器对象相比,它可以节省内存和CPU。当然,可以使用更少的代码来实现相同的功能。现在您可以开始重构您的代码。如果看到类似: ,可以将其替换为生成器函数: 生成器表达式是列表推送。生成器版本看起来像列表理解,但返回生成器对象而不是列表对象。next()
方法时,它可以返回容器中的下一个值。 __iter__
和 __next__()
对象(在 python2 中实现为 )的所有方法 __iter__ 的任何实现 返回自己的迭代器,
__next__
. 容器值中的下一项,如果容器中没有其他元素,则抛出 StopIteration 异常。他们如何实施并不重要。 itertools
返回一个迭代器对象。>>> from itertools import count
>>> counter = count(start=13)
>>> next(counter)
13
>>> next(counter)
14
>>> from itertools import cycle
>>> colors = cycle(['red', 'white', 'blue'])
>>> next(colors)
'red'
>>> next(colors)
'white'
>>> next(colors)
'blue'
>>> next(colors)
'red'
>>> from itertools import islice
>>> colors = cycle(['red', 'white', 'blue']) # infinite
>>> limited = islice(colors, 0, 4) # finite
>>> for x in limited:
... print(x)
red
white
blue
red
class Fib:
def __init__(self):
self.prev = 0
self.curr = 1
def __iter__(self):
return self
def __next__(self):
value = self.curr
self.curr += self.prev
self.prev = value
return value
>>> f = Fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
__iter__
)和迭代器(因为它实现了 __iter__
)和迭代器(因为它实现了 ❀ ❀方法)。实例变量 prev
和 curr
用户维护迭代器中的状态。每次调用 next()
方法时,都会完成两件事: next() 方法的状态
结果当前通话。 Generator(生成器)
__iter__()
和__next__()
,只需要一个”关键字 Generator必须是迭代器(下面是不正确的) ),所以任何生成器也会以延迟加载模式返回值。使用生成器实现斐波那契数列的一个示例是:
def fib():
prev, curr = 0, 1
while True:
yield curr
prev, curr = curr, curr + prev
>>> f = fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
fib
是一个常规的 Python 函数。其特别之处在于函数体中没有关键字return
,函数Value的返回是一个生成器对象。执行f=fib()
时,返回一个生成器对象。此时,函数体中的代码将不会被执行。里面的代码只有在下次显式或隐式调用时才会执行。 。 def something():
result = []
for ... in ...:
result.append(x)
return result
def iter_something():
for ... in ...:
yield x
生成器表达式(生成器表达式)
>>> a = (x*x for x in range(10))
>>> a
<generator object <genexpr> at 0x401f08>
>>> sum(a)
285
总结
__iter__
方法,该方法返回一个迭代器对象。 __next__
和 __iter__
方法。迭代器不会一次返回所有值。元素被加载到内存中,但结果会根据需要返回。生成器return
传递,而是通过yield
传递。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。