Python学习-迭代器、生成器

一、迭代器

1. 可迭代对象

我们知道字符串、列表、元组、字典、集合都可以使用for语句进行循环遍历,然后输出每一个元素,这些都是可迭代对象。

检查对象是否是可迭代对象可以用两种方式去判断:

(1)使用dir()查看对象包含的方法和函数, 如果能找到__iter__, 那么这个对象就是一个可迭代对象

>>> lst = ['a', 'b', 'c']
>>> dir(lst)  #查看对象包含的方法和函数
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> dir(list)  #查看类中声明的方法和函数
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>>

(2)使用isinstance进行判断

>>> from collections import Iterable
>>> lst = ['a', 'b', 'c']
>>> isinstance(lst, Iterable) #结果为True,为可迭代对象
True

iterable翻译: 可迭代的; 可重复的; 迭代的

此处只查看了列表类型对象, 其他类型的对象可以自己尝试.

2. 迭代器

概念: 可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator

所谓的迭代器就是具有next方法的对象. 在调用next方法时, 迭代器会返回它的下一个值. 如果next方法被调用, 但迭代器没有值可以返回, 就会引发一个StopIteration异常.

迭代器和可迭代对象有什么区别:

(1) 可迭代对象不一定是迭代器, 但迭代器一定是可迭代对象

(2) 可迭代对象有iter方法, 迭代器有iter和next方法; 可以使用iter方法将可迭代对象转为迭代器

(3) 迭代器是惰性的, 只有当你使用next方法去取值的时候, 它才会返给你一个值

判断对象是否是迭代器:

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance(['a', 'b'], Iterator)
False
>>> isinstance('hello', Iterator)
False

>>> g = (x * 2 for x in range(5))
>>> isinstance(g, Iterator)
True
>>> next(g)
0
>>> next(g)
2
>>> next(g)
4
>>> next(g)
6
>>> next(g)
8
>>> next(g)  # 没有值返回时, 抛出异常StopIteration
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

使用iter方法(或__iter__)将对象变为迭代器:

>>> lst = ['a', 'b', 'c']
>>> isinstance(lst, Iterator)
False
>>> lst_g = lst.__iter__()
>>> isinstance(lst_g, Iterator)
True
>>> for ele in lst_g:
...     print(ele)
...
a
b
c
>>> dic = {'a': 1, 'b': 2}
>>> isinstance(dic, Iterator)
False
>>> dic_g = iter(dic)
>>> isinstance(dic_g, Iterator)
True

小结:

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如listdictstr等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

二、生成器

1. 先介绍一下列表生成式 (内容粘贴自廖雪峰老师的官方网站)

列表生成式,是Python内置的非常简单却强大的可以用来创建list的生成式。

列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式。

举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用list(range(1, 11))

>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

但如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?方法一是循环:

>>> L = []
>>> for x in range(1, 11):
...    L.append(x * x)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上面的list:

>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。

for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:

>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

还可以使用两层循环,可以生成全排列:

>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

 2. 生成器

通过列表生成式我们可以快速创建一个列表,这种方法生成列表,它会一次性的返回给我们全部元素,想想如果列表包含100万个元素,一次性返回会占用很大的内存空间,如果我们仅仅需要访问前面几个元素,这种方式生成的列表就比较浪费内存空间了。有没有一种方式,按照我们的需要,访问时给我们返回元素,不要像列表生成式一样一次全部返回。生成器就可以满足我们的这种需求,按需返回,可以调用next方法,生成器会返回它的下一个值,当没有值可以返回时,抛出StopIteration异常。实际使用中,我们一般使用for循环对生成器进行迭代。

在python中创建生成器:

(1)生成器函数

def func():
    print('hello world')
    yield 'world'              #与定义的普通函数没有区别,只是含有yield关键字;函数中包含yield关键字即为生成器函数
    print('hello china')
    yield 'china'

g = func()
print(next(g))
print(next(g))
print(g)
# 输出结果
hello world
world
hello china
china
<generator object func at 0x108ad3468>

(2)生成器表达式

只要把一个列表生成式的[]改成(),就创建了一个generator。

g = (x * x for x in range(5))
print(g)
for i in g:
    print(i)
输出结果:
<generator object <genexpr> at 0x10a845468>
0
1
4
9
16


lst = ['a', 'b', 'c', 'd']
g2 = (x * 2 for x in lst)
print(g2)
while 1:
    try:
        print(next(g2))
    except StopIteration:
        break
输出结果:
<generator object <genexpr> at 0x10395b468>
aa
bb
cc
dd
原文地址:https://www.cnblogs.com/gandoufu/p/9330473.html