Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)

Stella981
• 阅读 671

一、切片(Slice)

       在很多编程语言中,针对字符串提供了很多截取函数(i.e.  substring),目的就是对字符串切片。python中没有针对字符串的截取函数,需要通过“切片”来完成。

    取一个list或tuple的部分元素可以用切片

      格式:  假定list或tuple组成的元素组名为m

                 m[起始值:终止值:步长]  

            说明:

    a. 起始值如果是0,可以省略,但是中间的冒号(:)一定要带上

    b. 起始值,终止值限定的是索引范围。

    c. 如果从前面开始取数,那么索引时不包括索引[终止值],因为索引时下标从0开始。

    d. 如果从后面开始取数,即倒数,如果m[-2:] 则取最后两个元素,如果m[-2:-1]则取倒数第二个元素,注意两者的区别。

    e. 不管从前面开始或从后面开始取数,最终取的元素个数为都为终止值-起始值。

               python支持m[-1]取倒数第一个元素,那么它同样支持倒数切片。

       tuple也可以用切片操作,操作结果仍是tuple。

      字符串也可以用切片操作,只是操作结果仍是字符串。字符串'xxx'也可以看成一种list,每个元素就是一个字符。

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)

二、迭代

       一个对象,可以通过for循环来遍历这个对象,这种遍历称为迭代。

可迭代对象:list, tuple,字典dict,字符串,生成器generator

1、如何判断一个对象是可迭代对象呢?方法:通过collections模块的Iterable类型判断;

1 from collections import Iterable
2 print(isinstance('abd',Iterable))  #字符串是否可迭代
3 
4 print(isinstance([1,2,4],Iterable))  #list是否可迭代
5 
6 print(isinstance(123,Iterable)) #整数是否可迭代

下面为在命令交互行测试代码:

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)


  在Python中,只要是可迭代对象,无论有无下标,都可以迭代,例如,list和tuple有下标,字典dict没有下标


2、字典dict迭代

      默认情况下,dict迭代的是key,for key in d.keys( ) 或 for  k   in  d.keys( )

如果要迭代value,可以用for  value  in  d.values( )  或 for  v   in  d.values( )

如果要同时迭代key和value,可以用for  k, v  in  d.items( ).

    下面是使用代码:

 1 d={'a':1,'b':2,'c':3} #这是一个dict
 2 for key in d:   # 遍历key,由于默认是key,所以 in d,如果默认不是key,就需要写成 in d.keys 3     print(key)
 4 for value in d.values():   #遍历每一个值
 5     print(value)
 6  # 遍历每一个值,这个跟上面的效果是一样的,只不过上面是value,这个是v,这都可以,
 7 # for 和in 中间使用value,那么print中也要用value,不能使用v,要保持一致
 8 for v in d.values():
 9     print(v)
10 for k,v in d.items():  #遍历key和值
11     print(k,v)

3、字符串也是可迭代对象,因此,也可作用于for 循环:

 1 for ch in 'abdf':
 2     print(ch)

综上,当我们使用for循环时,只要作用的对象是一个可迭代对象,for循环就可以正常运行,而不必关心该对象是list还是其他数据类型。

4、在Python中实现类似JAVA那样的下标循环,要怎么做?

enumerate( )函数

可以把一个list变成索引-元素对,因此在for循环中可以同时迭代索引和元素本身。

1 #python内置的enumerate函数可以把一个list变成索引-元素对,
2 #这样就可以在for循环中同时迭代索引和元素本身
3 for i, value in enumerate(['a','b','c']):
4     print(i,value)

Python的for循环里,同时引用两个变量是很常见的,代码如下:

1 for x, y  in [(1,1),(2,3),(3,9)]:
2     print(x,y)

迭代小结

1、Python中迭代是通过for ……in 来完成的,C语言和JAVA迭代list是通过for循环实现的。

2、Python的for循环抽象程度高于C的for循环,因为Python的for循环不仅可以用在list或tuple上,还可以作用在其他可迭代对象上。

3、enumerate函数把一个list变成索引-元素对

三、列表生成式

      是Python内置的可以用来创建list的生成式。

 使用方法:  前面一部分是对元素进行的操作,最后面一部分是对元素进行判断

1 print([x*x for x in [1,2,3,4,5]])
2 
3 print([x*x for x in range(1,11)])
4 
5 print([x*x for x in range(1,11) if x % 2 == 0 ])
6 
7 print([m+n for m in 'ABC' for n in 'XYZ'])

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)

实例:列出当前目录下的所有文件和目录名

1 import  os # 导入os模块
2 print([d for d in os.listdir('.')])

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)

实例:把list中所有的字符串变成小写

1 L=['hello','world','IBM','Apple']
2 print([s.lower() for s in L])

 注意:s.lower()中的括号一定要带上,否则会报错

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)

列表生成式练习题目:把一个list中的所有字符串变成小写。  

 思路: 如果list中既包含字符串,又包含数字,由于非字符串类型没有Lower()方法,所以列表生成式会报错:

1 L1=['Hello','World',18,'Apple']
2 print([s.lower() for s in L1 ])

报错信息:

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)

可以使用isinstance()函数判断一个变量是不是字符串,下面为修改后并测试成功的代码:

1 L1=['Hello','World',18,'Apple']
2 print([s.lower() for s in L1 if isinstance(s,str) == True])

四、生成器generator

        如果列表元素可以按照某种算法推算出来,那我们因此可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。

在Python中,这种一边循环 一边计算的机制,称为生成器:generator。

创建generator的方法

  (1)把一个列表生成式的中括号[ ]改成**小括号( )**,就创建了一个generator。

1 #这个是创建list
2 L=[x*x for x in range(10)]
3 print(L)
4 #这个是创建生成器generator,使用的是小括号
5 g=(x*x for x in range(10))
6 print(g)

(2)创建generator方法:yield关键字

generator保存的是算法,如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。

如果一个函数定义中包含了yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。

注意:这里最难理解的是,generator和函数的执行流程不一样。

函数是顺序执行,遇到return语句或者最后一行函数语句就返回。

而generator函数,在每次调用next( )的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。


定义完一个generator后 ,当调用该generator时,首先要生成一个generator对象,然后才能使用next( )函数不断获得下一个返回值。


生成器generator中如何访问每个元素?

>>>方法一:   NEXT()函数

注意:每次调用next( g ),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多元素时,抛出StopIteration的错误。

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)

>>>方法二:For循环

因为通过Next( )函数太繁琐了,而且generator也是可迭代对象(Iterable),所以可以使用for循环来访问每个元素:

1 g=(x*x for x in range(10))
2 for n in g:
3     print(n)

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)


案例解析:获得生成器中的return返回值

 1 def odd():
 2     print('step 1')
 3     yield 1
 4     print('step 2')
 5     yield(3)
 6     print('step 3')
 7     yield(5)
 8     return 'done'
 9 c=odd()
10 while True:
11     try:
12         # i=next(c)
13         # print(i)    #i=next(c),print(i)这两句的效果和print(next(c))的效果相同,都是通过next函数访问每个元素
14         # print(next(c))   #next函数访问元素时,当取到最后一个元素,再继续往下取时,就会报错,此时会跳转到except语句处执行
15                          #所以上面使用next函数访问的两种方法都会跳转到except语句处,获得return语句的返回值
16         for i in c:   #使用for循环时,不会跳转到except语句处,所以拿不到定义的generator中的return语句的返回值
17             print(i)
18     except StopIteration as e:
19         print("Generator return value:",e.value)
20         break

 左边是next函数运行返回的结果,右边是for循环的结果,只有next函数返回了return语句中的返回值

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)       Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)

案例解析:斐波那契数列

 1 def fib(max):
 2     n, a, b = 0, 0, 1
 3     while n < max:
 4         yield b
 5         a, b = b, a + b
 6         n = n + 1
 7     return 'done'
 8 
 9 print("下面展示三种访问生成器元素的方式:")
10 print("通过for循环访问元素:")
11 for i in fib(6):
12     print(i)
13 
14 print("通过next函数访问元素:")
15 o=fib(6) #这相当于先生成一个generator对象,然后使用next函数调用每一个元素
16 print(next(o))
17 print(next(o))
18 print(next(o))
19 print(next(o))
20 print(next(o))
21 print(next(o))
22 
23 
24 
25 print("通过fib(6)访问元素:")   #通过next(fib(6))访问,相当于每次调用next时都是调用一个新的生成器generator
26 print(next(fib(6)))
27 print(next(fib(6)))
28 print(next(fib(6)))
29 print(next(fib(6)))
30 print(next(fib(6)))
31 print(next(fib(6)))
32 
33 print("获得return返回值的访问方式:")
34 g=fib(6)
35 while True:
36     try:
37         print("g:",next(g))
38     except StopIteration as e:
39         print("Generator return value:",e.value)
40         break

上面展示了不同方法的运行结果:

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)


生成器generator的小结:

1、使用类似列表生成式创建generator时,注意是小括号

2、使用函数创建generator时,函数定义中要有yield关键字

3、generator保存的是算法。

4、访问generator中的每个元素:next( )或for循环

5、generator是可迭代对象Iterable

6、每次调用next( g ),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多元素时,抛出StopIteration的错误。

当创建一个generator后,基本上不会调用next( ),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

五、迭代器

可直接作用于for循环对象统称为可迭代对象:Iterable.

    可直接作用于for循环的数据类型有:

第一类是集合数据类型,如list, tuple, dict, set, str等。

第二类是generator, 包括生成器和带 yield 的generator function.

 

迭代器( Iterator )的定义:

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

注意:可迭代对象和迭代器都是指对象

isinstance( )函数:

      使用isinstance( )函数来判断一个对象是否是Iterable对象或Iterator对象

iter( )函数:

    生成器都是Iterator对象,但list, dict,  str虽然是Iterable,却不是Iterator。可以使用iter( )函数把list, dict, str等Iterable转换成Iterator

下面使用next也可以遍历list中每一个元素:

1 it=iter([1,2,3,4,5,6])
2 print(next(it))
3 print(next(it))
4 print(next(it))
5 print(next(it))
6 print(next(it))

在命令交互行模式下测试:

Python —— 函数高级特性(切片、迭代、列表生成式、生成器、迭代器)

为什么list, dict, str等数据类型不是Iterator?

      这是因为Iterator对象表示的是一个数据流,Iterator对象可以被next( )函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能通过next( )函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,i.e. 全体自然数,而使用list是永远不可能存储全体自然数的。

小结

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

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

3、列表list、字典dict、字符串str都是Iterable类型但不是Iterator类型,不过可以通过iter( )函数进行转换

4、Python的for循环本质上就是通过不断调用next( )函数实现的

参考:廖雪峰的官方网站:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143178254193589df9c612d2449618ea460e7a672a366000

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Stella981 Stella981
2年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这