Python中的迭代协议

从左到右扫描对象的可以简单称为迭代,迭代工具包括for循环、列表解析、in成员关系测试以及map内置函数等。可迭代对象基本上就是序列观念的通用化,如果对象是实际保存的序列或者说可以在迭代工具环境中一次产生一个结果的对象就看做是可迭代的(iterable),可迭代对象包括实际序列和按照需求而计算的虚拟序列。

有__next__方法的对象会前进到下一个结果,而在结尾印发StopIteration,在Python中任何这类对象都认为是可迭代的。

1) 例如:for line in open('script1.py')中的line末尾已经有一个'\n'换行字符了,所以默认打印时会多输出一个空行。这是读取文本文件的最佳方式,原因有:方法简单运行快;占用内存较少(调用readlines方法一次性载入内存);基于迭代器的版本会不断更新(性能可能更快,Python3.0通过重写I/O支持Unicode文本从而这一优点不那么明显,这样也更少依赖于系统)。

while循环调用readline方式虽然占用内存小了,但是速度更慢一些。因为迭代器是以C语言的速度运行的,而while循环则是通过Python虚拟机运行Python字节码的。任何时候把Python换成C代码速度应该更快。然而并非绝对如此,尤其是Python3.0中,什么技术?

2) Python3.0提供了内置函数next,它会自动调用一个对象的__next__方法。对一个可迭代对象X,调用next(X)等同于X.__next__()。

迭代协议注意点:当for循环(其他迭代工具也是)开始时,会通过for循环传给iter内置函数,以便从可迭代对象(列表及很多内置对象)中获得一个迭代器,迭代器含有__next__方法。文件对象就是自己的迭代器,也就是说文件对象有自己的__next__方法。

l = [1, 2, 3]

i = iter(l)

i.__next__() # 返回1

f = open('data.txt')

f.__next__() # 返回第一行,不需要iter函数

iter(f) is f # 返回True

while true:

    x = next(i)

    print(x)

迭代工具有时候针对用户定义的类不同地工作,重复的索引一个对象而不是运行迭代协议,具体?

3) 字典中的迭代器

假如d是一个字典对象,在Python2.X中d.keys()返回一个列表对象。在Python新版本中(3.0吗),字典有一个迭代器,在迭代环境中,会自动一次返回一个键。i =iter(d)返回d.keys的一个迭代器,等效于i = iter(d.keys())。d.keys()不能直接调用__next__方法,所以d.keys()返回的不是一个迭代器而是一个可迭代对象(可使用迭代工具,因为迭代工具自动调用iter函数返回迭代器)。

d = {'a':1, 'b':2}

s1 = sorted(d) #s1是一个d的键视图排序后的列表

shelves和os.popen(可以调__next__()方法,但不可以next(os.popen(<参数>),这不太符合常理,因为next调用__next__,这是一个实现问题)结果也是可迭代的。可迭代的对象有的本身就是迭代器,有的自身不是迭代器(例如列表、字典键)。

enumerate('spam')返回的是一个迭代器,可以直接调用__next__方法,也可以使用next函数调用。

4) 列表解析

列表解析表达式创建新的列表对象,比手动的for循环语句运行的更快(往往速度快一倍,因为列表解析的迭代在解释器内部是以C语言的速度执行的)。列表解析语法源自于集合理论表示法中的一个结构,该结构对集合中的每个元素应用一个操作。

列表解析就像一个反向的for循环,还有表现力强的有点(支持for前复杂的表达式运算)。

5) 文件列表解析

f = open('script1.py')# Python扫描文件并自动构建了操作结果的一个列表。

l =f.readlines() # 此方法返回一个列表对象,文件中使用line[:-1]去掉最后一个换行符需要确保所有的行都正确结束才可。

6) 列表解析可以添加if过滤子句(列表解析扩展)。通常,我们总是可以把一个列表解析转换为一条for语句,通过逐步附加并进一步缩进每个后续的部分。例如:

res =[line.rstrip() for line in open('script.py') if line[0] == 'p']

这个等同于下面的代码(这里是为了方便理解扩展列表解析),但是上面的代码运行的更快。

res = []

for line inopen('script.py'):

    if line[0] == 'p':

        res.append(line.rstrip())

实际上列表解析的完整的语法允许任意数目的for子句,每个子句有一个可选的相关的if子句。

列表解析要对语句进行循环时,它们就是和函数相关联的。

7) 迭代协议

可迭代对象支持迭代协议(或者说实现了迭代协议),迭代工具(迭代环境)在对象中从左到右扫描,使用了迭代协议。for循环、列表解析、in成员关系测试、map内置函数、sorted内置函数、zip内置函数也使用了迭代协议(所以也是迭代环境,迭代工具)。

list(map(str.upper,open('script.py')) # map类似于列表解析,但它更具局限性,因为它需要一个函数而不是一个任意的表达式,Python3.0中它返回一个可迭代的对象自身,

sorted(open('script.py'))# 在Python3.0中sorted返回一个真正的列表而不是一个可迭代对象

list(filter(bool,open('script.py')) # filter选择一个函数为真的项

importfunctools, operator

functools.reduce(operator.add,open('script.py')) # 将每行连接起来(中间无分隔符)

sum,any,all,max(可用于文件,取最大字符串值的行,min类似),min函数也支持可迭代协议。list和tuple内置函数也可以从可迭代对象创建一个新的对象。字符串的join方法(将该字符串放到可迭代对象的中间),甚至包括序列赋值也使用了迭代协议。

dict(zip(<可迭代对象1>, <可迭代对象2>)) # 根据可迭代的zip结果创建字典

set(open('script.py'))# 根据可迭代对象创建集合

还有一种函数调用中用到的一种特殊的*arg形式的迭代,它会把一个集合的值解析为单个的参数。例如函数f(a, b, c),调用可以f(*[1, 2, 3])将列表解析成三个参数。

内置函数range和字典视图对象它们返回可迭代对象而不是处理它们。

8) Python3中的可迭代对象,在Python2.X中的列表对象在Python3.X中是可迭代对象,例如字典方法keys,values,items返回的对象,range,map,zip,filter返回的对象(可以节省内存空间吗?)。

range迭代器:range函数在Python3.0中返回可迭代对象,只支持迭代,索引和len函数,不支持其他的序列操作。

map/zip/filter迭代器:这几个函数返回结果是一个自身的迭代器(遍历一次结果之后就用完了,也就是不能在他们的结果上拥有保持不同位置的多个迭代器)。

猜你喜欢

转载自blog.csdn.net/XueminXu/article/details/80495715