Python迭代器、列表解析、生成器表达式、产生偏移和元素用法详解

Python迭代器、列表解析、生成器表达式、产生偏移和元素用法详解

1、Python迭代器

迭代器(iterator)有时又称游标(cursor),是程式设计的软件设计模式,可在容器物件(container,例如链表或阵列)上遍访的接口,设计人员无需关心容器物件的内存分配的实现细节。

各种语言实作迭代器的方式皆不尽同,有些面向对象语言,像Java, C#, Ruby, Python, Delphi都已将迭代器的特性内建语言当中,完美的跟语言整合,我们称之隐式迭代器(implicit iterator),但像C++语言本身就没有迭代器的特色,但STL仍利用模板实作了功能强大的迭代器。STL容器的数据的内存地址可能会重新分配(reallocate),与容器绑定的迭代器仍然可以定位到重新分配后的正确的内存地址。

迭代器另一方面还可以整合生成器(generator)。有些语言将二者视为同一接口,有些语言则将之独立化。

在 Python 中,迭代器是遵循迭代协议的对象。使用 iter() 从任何序列对象中得到迭代器(如 list, tuple, dictionary, set 等)。另一种形式的输入迭代器是generator。

要使得迭代器指向下一个元素,则使用成员函数next()(Python 2)或函数__next__()(Python 3)。当没有元素时,则引发 StopIteration异常。若要实现迭代器,则需要在类中定义next()(Python 2)或__next__()( Python 3)。

例:Python迭代器使用示例

In [1]: l1 = [1,2,3]

In [2]: i1 = l1.__iter__()

In [3]: i1.next()

Out[3]: 1

In [4]: i1.next()

Out[4]: 2

In [5]: i1.next()

Out[5]: 3

In [6]: i1.next()

---------------------------------------------------------------------------

StopIteration                             Traceback (mostrecent call last)

<ipython-input-6-be7912f76fe0> in<module>()

----> 1 i1.next()

StopIteration:

2、Python列表解析

在需要改变列表而不是需要新建某列表时,可以使用列表解析。

1)、语法格式

[expr for iter_var in iterable]

[expr for iter_var in iterable if cond_expr]

第一种语法:首先迭代iterable里所有内容,每一次迭代,都把iterable里相应内容放到iter_var中,再在表达式中应用该iter_var的内容,最后用表达式的计算值生成一个列表。

第二种语法:加入了判断语句,只有满足条件的内容才把iterable里相应内容放到iter_var中,再在表达式中应用该iter_var的内容,最后用表达式的计算值生成一个列表。

2)、用法示例

例1:不加条件的列表解析示例

In [1]: l1 = [1,2,3,4,5]

In [2]: l2 = []

In [3]: for i in l1:

  ...:     l2.append(i**2)

  ...:    

In [4]: print l2

[1, 4, 9, 16, 25]

In [5]: t3 = [ i**2 for i in l1 ]

In [6]: print t3

[1, 4, 9, 16, 25]

In [7]: [ i**2 for i in l1 ]

Out[7]: [1, 4, 9, 16, 25]

例2:加入条件的列表解析示例

In [8]: l3 = [ i**2 for i in l1 if i >=3 ]

In [9]: print l3

[9, 16, 25]

In [10]: for i in [ i**2 for i inrange(1,11) ]: print i/2,

0 2 4 8 12 18 24 32 40 50

In [11]: for i in [ i**2 for i inrange(1,11) if i % 2 == 0 ]: print i/2,

2 8 18 32 50

例3:列表解析应用1:使用列表解析打印/var/log目录下以'.log'结尾的文件

In [1]: import os

In [2]: files = os.listdir('/var/log')

In [3]: s1 = 'test.log'

In [4]: s1.endswith('.log')

Out[4]: True

In [5]: s2 = 'test'

In [6]: s2.endswith('.log')

Out[6]: False

In [7]: logs = [ i for i in fil

%%file file    files   filter 

In [7]: logs = [ i for i in files ifi.endswith('.log') ]

In [8]: print logs

['Xorg.9.log', 'Xorg.1.log','keepalived.log', 'anaconda.ifcfg.log', 'pm-powersave.log','anaconda.storage.log', 'mysqld.log', 'boot.log', 'anaconda.log', 'dracut.log','Xorg.0.log', 'anaconda.yum.log', 'wpa_supplicant.log', 'yum.log','Xorg.2.log', 'anaconda.program.log']

例4:列表解析应用2:根据已经有列表,高效生成新列表的方式

In [1]: l1 = ['x','y','z'];l2 = [1,2,3]

In [2]: l3 = [ (i,j) for i in l1 for j inl2 ]

In [3]: print l3

[('x', 1), ('x', 2), ('x', 3), ('y', 1),('y', 2), ('y', 3), ('z', 1), ('z', 2), ('z', 3)]

In [4]: l4 = [ (i,j) for i in l1 for j inl2 if j != 1 and i != 'x' ]

In [5]: print l4

[('y', 2), ('y', 3), ('z', 2), ('z', 3)]

 3、Python生成器表达式

生成器表达式是在python2.4中引入的,当序列过长,而每次只需要获取一个元素时,

应当考虑使用生成器表达式而不是列表解析。生成器表达式的语法和列表解析一样,只不过生成器表达式是被()括起来的,而不是[]

生成器表达式并不真正创建数字列表,而是返回一个生成器,这个生成器在每次计算出一个条目后,把这个条目“产生”(yield)出来。生成器表达式使用了“惰性计算”(lazy evaluation,也有翻译为“延迟求值”,

这种按需调用call by need的方式翻译为惰性更好一些),只有在检索时才被赋值( evaluated),

所以在列表比较长的情况下使用内存上更有效。

1)、语法格式

(expr for iter_var in iterable)

(expr for iter_var in iterable ifcond_expr)

2)、用法示例

例1:Python生成器表达式用法示例

In [1]: y1 = ( i**2 for i in range(1,4))

In [2]: y1.next()

Out[2]: 1

In [3]: y1.next()

Out[3]: 4

In [4]: y1.next()

Out[4]: 9

In [5]: y1.next()

---------------------------------------------------------------------------

StopIteration                             Traceback (mostrecent call last)

<ipython-input-5-e528b641d5f6> in<module>()

----> 1 y1.next()

StopIteration:

例2:Python生成器对象在for循环中的使用

In [6]: for j in ( i**2 for i inrange(1,11)):print j/2,

0 2 4 8 12 18 24 32 40 50

 4、Python产生偏移和元素

1)、生成器对象生成函数enumerate()

range()函数可在非完备遍历中用于生成索引偏移,而非偏移处的元素

enumerate()函数同时产生偏移索引和偏移元素,此内置函数返回一个生成器对象

enumerate(iterable[, start])

2)、用法示例:

例1:自定义url,使用enumerate()函数打印由索引和单个字符构成的元组

In [1]: url = 'web2.field.com'

In [2]: enumerate(url)

Out[2]: <enumerate at 0x11d1140>

In [3]: g1 = enumerate(url)

In [4]: g1.next()

Out[4]: (0, 'w')

In [5]: g1.next()

Out[5]: (1, 'e')

In [6]: g1.next()

Out[6]: (2, 'b')

例2:使用range()函数打印1~10中的奇数

In [7]: range(1,11,2)

Out[7]: [1, 3, 5, 7, 9]

例3:enumerate()函数偏移索引用法

In [8]: g1 = enumerate(url,4)

In [9]: g1.next()

Out[9]: (4, 'w')

In [10]: g1.next()

Out[10]: (5, 'e')

In [11]: g1.next()

Out[11]: (6, 'b')

5、总结说明:

1. 当只是需要执行一个循环的时候尽量使用循环而不是列表解析,这样更符合python提倡的直观性。

for item in sequence:

process(item)

2. 当有内建的操作或者类型能够以更直接的方式实现的,不要使用列表解析。

例如复制一个列表时,使用:L1=list(L)即可,不必使用:

L1=[x for x in L]

3. 当序列过长, 而每次只需要获取一个元素时,使用生成器表达式。

4. 列表解析的性能相比要比map要好,实现相同功能的for循环效率最差(和列表解析相比差两倍)。

5. 列表解析可以转换为for循环或者使用map(其中可能会用到filter、lambda函数)表达式,但是列表解析更为简单明了,后者会带来更复杂和深层的嵌套。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值