一、迭代器
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
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是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