前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python3学习笔记 | 十六、Python的语句与语法-迭代器和解析(1)

Python3学习笔记 | 十六、Python的语句与语法-迭代器和解析(1)

作者头像
TeamsSix
发布2019-09-24 17:07:46
7080
发布2019-09-24 17:07:46
举报
文章被收录于专栏:TeamsSix的网络空间安全专栏

一、迭代器

1、初探

之前章节中,我们看到for语句可以Python任何序列类型,包括列表、元祖以及字符串。如下所示:

代码语言:javascript
复制
>>> for i in [1,2,3]:print(i,end=' ')
...
1 2 3
>>> for i in (1,2,3):print(i,end=' ')
...
1 2 3
>>> for i in '123':print(i,end=' ')
...
1 2 3

下面我们继续看文件迭代器、手动迭代(iter, next)、其它内置类型迭代器。

2、文件迭代器

回忆一下之前章节,文件访问方式有如下:

.read(): 一次性读取全部内容。

.readline(): 一次读取一行。

.readlines(): 生成列表,每一行是每个元素。

.next(): 跟readline()差不多,但读取完之后报错。 next()报错,为StopIteration。在Python中任何这类对象都认为是可迭代的。在Python里迭代工具(比如for)会调用next()来获取数据,并以StopIteration来确认何时离开。

代码语言:javascript
复制
for line in open(<filename>):
 print(line, end = '')

因为每个元素在最后包涵\n(换行符),因此print函数结尾需要取消结尾中的换行。

注: 尽量不要使用readlines()函数,因为这个会一次性的把所有内容读取到内存里(转换为列表),运行速度会比较慢。最好使用readline或者迭代文件方法。

3、手动迭代

为了支持手动迭代代码,Python支持next()函数,它会自动读取next()函数。next(X)等同于X.next()。

代码语言:javascript
复制
f = open(<filename>)
 next(f)

这个会从第一行开始读取内容。

从技术角度来讲,迭代协议里,当使用for函数进行迭代时,会传递给iter内置函数,以便可迭代对象中获取迭代器。返回的对象有需要有next()方法。

代码语言:javascript
复制
>>> L = [1,2,3]
>>> i = iter(L)
>>> next(i)
1
>>> next(i)
2
>>> next(i)
3
>>> next(i)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

对于文件来说,不需要转换成iter类型的这一步:

代码语言:javascript
复制
>>> file = open(r'C:\Test\test.txt')
>>> file is iter(file)
True

因为文件对象就是自己的迭代器,但列表,元祖,字符串等就不是了。

代码语言:javascript
复制
>>> str = '123' ; list = [1,2,3] ; tuple = (1,2,3)
>>> str is iter(str)
False
>>> list is iter(list)
False
>>> tuple is iter(tuple)
False

4、其他内置类型迭代器

除了文件以及像列表这样的实际的序列外,其它类型也有其适用的迭代器。例如,遍历字典键的经典方法是明确地获取其键的列表。

代码语言:javascript
复制
>>> dict = {'a': 1 ,'b' : 2 ,'c' : 3}
>>> for key in dict.keys() :
...     print(key,dict[key])
...
a 1
b 2
c 3

二、列表解析

1、初探

遍历列表时,使用for循环来修饰它:

代码语言:javascript
复制
>>> list = [1,2,3]
>>> for i in range(len(list)) :
...     list[i] += 10
...
>>> list
[11, 12, 13]

这个是有效的,但不是“最佳实践”。我们可以使用产生所需结果列表的一个单个表达式来完成上面循环:

代码语言:javascript
复制
>>> list = [1,2,3]
>>> list = [i + 10 for i in list]
>>> list
[11, 12, 13]

2、列表解析基础知识

从之前的例子开始分析:list1 = [i + 10 for i in list1]

这个先是运算 [i + 10 for i in list1]之后,再把此赋值给list1。我们来看里面是如何运算:

先是对list1进行迭代,每次把单个值符给i,再进行i + 10,成为新列表的单个元素。这个相当于:

代码语言:javascript
复制
tmp = []
for i in list1:
tmp.append(i+10)
list1 = tmp

可以认为是倒过来的for循环语句。

3、在文件上使用列表解析

代码语言:javascript
复制
>>> file = open(r'C:\Test\test.txt').readlines()
>>> file
['DoraEmon\n', 'Daxiong\n', 'JingXiang']

在这里发现,每行最后都会有\n换行符,这个时候我们可以使用列表解析来进行去除换行符的操作。

代码语言:javascript
复制
>>> file = [line.strip() for line in file]
>>> file
['DoraEmon', 'Daxiong', 'JingXiang']

或更简单

代码语言:javascript
复制
>>> file = [line.strip() for line in open(r'C:\Test\test.txt')]

还可以进行更多操作:

代码语言:javascript
复制
>>> file = [line.strip().upper() for line in open(r'C:\Test\test.txt')]
>>> file
['DORAEMON', 'DAXIONG', 'JINGXIANG']

4、扩展的列表解析语法

扩展语法是在循环基础上,添加了条件:

代码语言:javascript
复制
>>> file = [line.strip().upper() for line in open(r'C:\Test\test.txt') if line[0] !='J']
>>> file
['DORAEMON', 'DAXIONG']

在这里,发现添加 if line[0] != J’的时候,不显示以 “ J “ 开头的行。

代码语言:javascript
复制
>>> [x+y for x in [1,2,3] for y in [10,20,30]]
[11, 21, 31, 12, 22, 32, 13, 23, 33]

我们会发现第二个for循环算是嵌套在第一个for循环。

三、其他迭代环境

map也可用在迭代中:

代码语言:javascript
复制
>>> list(map(str.upper, open(r'C:\Test\test.txt')))
['DORAEMON\n', 'DAXIONG\n', 'JINGXIANG']

map函数是把后面的可迭代的每个值当作前面的参数传入。在Python3开始正式引入map,之前版本,python2.7也可以使用,但map可以直接返回列表,不需要使用list函数进行转换。后续章节中会继续讲解。上面的可以如下解释:

代码语言:javascript
复制
>>> tmp = []
>>> for line in open(r'C:\Test\test.txt'):
... tmp.append(str.upper(line))
...
>>> tmp
['DORAEMON\n', 'DAXIONG\n', 'JINGXIANG']

相应的,也有sorted,会对迭代对象进行排序后生成列表。

代码语言:javascript
复制
>>> sorted(open(r'C:\Test\test.txt'))
['Daxiong\n', 'DoraEmon\n', 'JingXiang']

enumerate也会对迭代对象进行运算后,生成可迭代对象。

代码语言:javascript
复制
>>> list(enumerate(open(r'C:\Test\test.txt')))
[(0, 'DoraEmon\n'), (1, 'Daxiong\n'), (2, 'JingXiang')]

enumerate就是在原有的顺序中添加序列号。除了这些,还有filter与reduce方法,这些再后续章节讲解用法。

代码语言:javascript
复制
>>> list(filter(bool,open(r'C:\Test\test.txt')))
['DoraEmon\n', 'Daxiong\n', 'JingXiang']
>>> import operator,functools
>>> functools.reduce(operator.add,open(r'C:\Test\test.txt'))
'DoraEmon\nDaxiong\nJingXiang'

sum、any、all、max、min也可使用迭代器。

any() 函数用于判断给定的可迭代参数 iterable 是否全部为 False,则返回 False,如果有一个为 True,则返回 True。元素除了是 0、空、FALSE 外都算 TRUE。

all() 函数用于判断给定的可迭代参数 iterable 中的所有元素是否都为 TRUE,如果是返回 True,否则返回 False。元素除了是 0、空、None、False 外都算 True。

代码语言:javascript
复制
>>> sum((1,2,3)),sum([4,5,6])
(6, 15)
>>> any([1,[],'True']), all([1,[],'True'])
(True, False)
>>> max([2,3,1]),min([2,3,1])
(3, 1)

list, tuple, join 都是可以对可迭代对象进行操作后输出:

代码语言:javascript
复制
>>> list(open(r'C:\Test\test.txt')),tuple(open(r'C:\Test\test.txt')),'**'.join(open(r'C:\Test\test.txt'))
(['DoraEmon\n', 'Daxiong\n', 'JingXiang'], ('DoraEmon\n', 'Daxiong\n', 'JingXiang'), 'DoraEmon\n**Daxiong\n**JingXiang')

四、Python3中新的迭代环境

从Python3.x开始,更注重迭代。在Python2.x里,很多函数生成的是列表方式:

代码语言:javascript
复制
>>> zip('abc','123')
[('a', '1'), ('b', '2'), ('c', '3')]

但在Python3.x开始是变成可迭代的特定对象:

代码语言:javascript
复制
>>> zip('abc','123')
<zip object at 0x102295148>
>>> list(zip('abc','123'))
[('a', '1'), ('b', '2'), ('c', '3')]

Python 3.x的这种方式,会延迟计算,在提取内容的时候计算结果。这样会节省内存空间,不需要提前计算后放进内存里。迭代对象,当迭代完成之后,不能再次读取。

代码语言:javascript
复制
>>> a = list(zip('abc','123'))
>>> for i in a: print(i, end=' ')
...
('a', '1') ('b', '2') ('c', '3') >>>
>>> for i in a: print(i, end=' ')
...
>>>

1、range

range从Python3.x开始变为迭代器。 Python 2.x:

代码语言:javascript
复制
>>> range(5)
[0, 1, 2, 3, 4]

Python 3.x:

代码语言:javascript
复制
>>> range(5)
range(0, 5)

所以,在Python 3.x要是需要生成一个有序列表,需要再次转换:

代码语言:javascript
复制
>>> list(range(5))
[0, 1, 2, 3, 4]

但也可以像列表一样使用:

代码语言:javascript
复制
>>> range(5)[1]
1
>>> range(5)[-1]
4

注:range可继续使用。

代码语言:javascript
复制
>>> r = range(7)
>>> for i in r :
...     print(i,end = ' ')
...
0 1 2 3 4 5 6 >>>
>>> for i in r :
...     print(i,end = ' ')
...
0 1 2 3 4 5 6 >>>

2、map、zip和filter

在Python3.x里,map、zip和filter也是使用迭代器来节约内存开销。但与range不同,使用一次之后,就不能再次使用。

代码语言:javascript
复制
>>> M = map(abs,(-1,3,7))
>>> list(M)
[1, 3, 7]
>>> list(M)
[]
>>> Z = zip((1,2,3),('a','b','c'))
>>> list(Z)
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> list(Z)
[]
>>> F = filter(bool,(1,'','True'))
>>> list(F)
[1, 'True']
>>> list(F)
[]

map() 函数会根据提供的函数对指定序列做映射。第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。

zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的对象,这样做的好处是节约了不少的内存。我们可以使用 list() 转换来输出列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。

filter() 函数用于过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用 list() 来转换。该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。

五、多个迭代器 vs 单个迭代器

之前看到的range,可以同时使用多个迭代器。这个叫range有着多个迭代器。可以进行索引。但其它的,只能迭代一次。

后续章节会看到各种迭代器,而且会说明如何生成两种迭代器。

六、字典视图迭代器

字典视图迭代器,与其它多个迭代器相似(在Python2.x里还是使用列表)

代码语言:javascript
复制
>>> dict = {'a':1,'b':2,'C':3}
>>> dict.keys()
dict_keys(['a', 'b', 'C'])
>>> dict.values()
dict_values([1, 2, 3])
>>> dict.items()
dict_items([('a', 1), ('b', 2), ('C', 3)])

在这里,迭代器都算是多个迭代器(Python3.4为基准)


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-02-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 TeamsSix 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、迭代器
  • 1、初探
  • 2、文件迭代器
  • 3、手动迭代
  • 4、其他内置类型迭代器
  • 二、列表解析
  • 1、初探
  • 2、列表解析基础知识
  • 3、在文件上使用列表解析
  • 4、扩展的列表解析语法
  • 三、其他迭代环境
  • 四、Python3中新的迭代环境
  • 1、range
  • 2、map、zip和filter
  • 五、多个迭代器 vs 单个迭代器
  • 六、字典视图迭代器
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档