文章目录

  • 一、迭代器
    • 1.1 什么是迭代器
    • 1.2 为何要有迭代器
    • 1.3 可迭代对象
    • 1.4 迭代器对象
    • 1.5 迭代器的优缺点
      • 1.5.1 优点
      • 1.5.3 缺点
  • 二、 for循环原理
  • 三、生成器
  • 四、三元表达式
  • 五、列表生成式
  • 六、生成器表达式
  • 七、函数的递归
  • 八、面向过程编程思想/范式
  • 九、匿名函数
  • 十、 map、reduce、filter

一、迭代器

1.1 什么是迭代器

迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而继续的

单纯的重复并不是迭代(举例:更新换代)

1.2 为何要有迭代器

迭代器是用来迭代取值的工具,而涉及到吧多个值循环取出来的类型有:列表,字符串,元祖,字典,集合,文件

l = [1,2,3]
i = 0
while i<len(l):print(l[i])i+=1

上述迭代取值的方式只适用于有索引的数据类型:列表,字符串,元祖

为了解决基于索引迭代取值的局限性。python必须提供一种能够不依赖于索引的取值方式,这就是迭代器

1.3 可迭代对象

从语法形式上讲,内置有__iter__方法的对象都是可迭代对象,字符串、列表、元组、字典、集合、打开的文件都是可迭代对象

1.4 迭代器对象

调用obj.iter()方法返回的结果就是一个迭代器对象(Iterator)。迭代器对象是内置有iternext方法的对象,打开的文件本身就是一个迭代器对象,执行迭代器对象.iter()方法得到的仍然是迭代器本身,而执行迭代器.next()方法就会计算出迭代器中的下一个值。 迭代器是Python提供的一种统一的、不依赖于索引的迭代取值方式,只要存在多个“值”,无论序列类型还是非序列类型都可以按照迭代器的方式取值

d = {'a': 1, 'b': 2}
d_iter = iter(d)
count = 0
while count < len(d):print(next(d_iter))count += 1
print('%' * 20)
d_iter = iter(d)   # 解决办法,再来一次
count = 0
while count < len(d):print(next(d_iter))count += 1

可迭代对象与迭代器对象详解

可迭代对象(可以转换成迭代器的对象):内置有__iter__方法对象可迭代对象.__iter__():得到迭代器对象
迭代器对象:内置有__next__方法并且内置有__iter__方法的对象迭代器对象.__next__():得到迭代器的下一个值迭代器对象.__iter__():得到迭代器的本身,说白了调了和没调一个样
测试:
d = {'a':1,'b':2}
d_iter = iter(d)
print(d_iter is iter(d_iter))可迭代对象:字符串,列表,元祖,字典,集合,文件对象
迭代器对象:文件对象

1.5 迭代器的优缺点

基于索引的迭代取值,所有迭代的状态都保存在了索引中,而基于迭代器实现迭代的方式不再需要索引,所有迭代的状态就保存在迭代器中,然而这种处理方式优点与缺点并存:

1.5.1 优点

  1. 为序列和非序列类型提供了一种统一的迭代取值方式
  2. 惰性计算:节省内存。迭代器对象表示的是一个数据流,可以只在需要时才去调用next来计算出一个值,就迭代器本身来说,同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,如列表,需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的

1.5.3 缺点

  1. 除非取尽,否则无法获取迭代器的长度。无法获取长度(只有在next完毕才知道到底有几个值)
  2. 一次性的,只能往后走,不能往前退。只能取下一个值,不能回到开始,更像是‘一次性的’,迭代器产生后的唯一目标就是重复执行next方法直到值取尽,否则就会停留在某个位置,等待下一次调用next;若是要再次迭代同个对象,你只能重新调用iter方法去创建一个新的迭代器对象,如果有两个或者多个循环使用同一个迭代器,必然只会有一个循环能取到值

二、 for循环原理

有了迭代器后,我们便可以不依赖索引迭代取值了,使用while循环的实现方式如下

goods=['mac','lenovo','acer','dell','sony']
i=iter(goods) #每次都需要重新获取一个迭代器对象
while True:try:print(next(i))except StopIteration: #捕捉异常终止循环break

for循环又称为迭代循环,in后可以跟任意可迭代对象,上述while循环可以简写为

goods=['mac','lenovo','acer','dell','sony']
for item in goods:   print(item)

for 循环在工作时,首先会调用可迭代对象goods内置的iter方法拿到一个迭代器对象,然后再调用该迭代器对象的next方法将取到的值赋给item,执行循环体完成一次循环,周而复始,直到捕捉StopIteration异常,结束迭代

for循环的工作原理

# for循环可以称之为迭代循环
d = {'a':1,'b':2}
for k in d:print(k)# 1. d.__iter__()得到一个迭代器对象
# 2. 迭代器对象.__next__()拿到一个返回值,然后将该返回值赋值给k
# 3. 循环往复步骤2,直到抛出异常,for循环户捕捉异常然后结束循环

三、生成器

就是自定义的迭代器

def func():print('第一次')yield 1print('第二次')yield 2g = func()
print(g)
# g 就是生成器,就是自定义的迭代器
# 会触发函数体代码的运行,然后遇到yield停下来
# 将yield后的值当做本次调用的结果返回
res = next(g)
print(res)

如何得到自定义的迭代器
在函数体内一旦存在yield关键字,调用函数并不会执行函数体代码
会返回一个生成器对象,生成器即自定义的迭代器

# 应用案例
def my_range(start, stop, step=1):while start < stop:yield startstart += stepfor x in my_range(1, 7, 2):print(x)

有了yield关键字,我们就有了一种自定义迭代器的实现方式。yield可以用于返回值,
但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数
用来返回多次值

def dog(name):print('狗准备吃东西')while True:# x 拿到的是yield接收的值# yield可以接收到外部send传过来的数据并赋值给xx = yieldprint('狗哥%s吃了%s' % (name, x))g = dog('旺旺')
# 针对表达式形式的yield,生成器对象必须事先被初始化一次,
# 让函数挂起在food=yield的位置,等待调用g.send()方法为函数体传值
# g.send(None)等同于next(g)
# next(g)
g.send(None)  # 等同于next(g)
g.send('一根骨头')

这里,最难理解的就是generator和函数的执行流程不一样
函数是顺序执行,遇到return语句或者最后一行函数语句就返回
而变成generator的函数,在每次调用next()的时候执行,
遇到yield语句暂停并返回数据到函数外,再次被next()调用时从上次返回的yield语句处继续执行

四、三元表达式

三元表达式是python为我们提供的一种简化代码的解决方案,语法如下

res = 条件成立时返回的值 if 条件 else 条件不成立时返回的值
def max2(x,y):if x > y:return xelse:return yres = max2(1,2)# 用三元表达式可以一行解决
x=1
y=2
res = x if x > y else y # 三元表达式

五、列表生成式

列表生成式是python为我们提供的一种简化代码的解决方案,用来快速生成列表

[expression for item1 in iterable1 if condition1]
或者:
[expression for item1 in iterable1]
l = ['muyi_nb', 'yimu_nb', 'lao_nb']
# 将所有小写字母转为大写
new_l = [x.upper() for x in l]
print(new_l)
# 取出所有的_nb
new_l = [x.split('_')[0] for x in l]
print(new_l)
new_l = [x.replace('_nb', '') for x in l if x=='yimu_nb']
print(new_l)
# 字典生成式
items = [('name','muyi'),('age',18),('sex','man')]
res = {k:v for k,v in items if k!='sex'}
print(res)# 集合生成式
keys = ['name','age','sex']
set1 = {key for key in keys}
print(set1,type(set1))

六、生成器表达式

创建一个生成器对象有两种方式,一种是调用带yield关键字的函数,另一种就是生成器表达式,与列表生成式的语法格式相同,只需要将[]换成()

(expression for item in iterable if condition)

对比列表生成式返回的是一个列表,生成器表达式返回的是一个生成器对象

>>> [x*x for x in range(3)]
[0, 1, 4]
>>> g=(x*x for x in range(3))
>>> g
<generator object <genexpr> at 0x101be0ba0>

对比列表生成式,生成器表达式的优点自然是节省内存(一次只产生一个值在内存中)

>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g) #抛出异常StopIteration

如果我们要读取一个大文件的字节数,应该基于生成器表达式的方式完成

with open('db.txt','rb') as f:nums=(len(line) for line in f)total_size=sum(nums) # 依次执行next(nums),然后累加到一起得到结果=

七、函数的递归

函数的递归调用:是函数嵌套调用的一种特殊形式

具体是指:在调用一个函数的额过程中又直接或者间接的调用本身

递归函数:就是函数内部自己调用自己

递归的本质就是循环

一段代码的循环运行的方案有两种

  1. while for 循环
  2. 递归的本质就是循环

递归最重要的就是找到出口(停止的条件),因为python会一直开辟内存空间

def f1(n):if n<5:print(n)n +=1f1(n)f1(0)
# 递归最大的层级是1000层
import sys# 查看层级
res = sys.getrecursionlimit()
print(res)
# 设置层级
sys.setrecursionlimit(1000)
# 虽然可以设置,但不建议去设置

扩展:在有些编程语言中,有尾递归优化,通过某种优化方式,在每进入进入下一层递归之前将之前的内存销毁,不会开辟更多内存空间,python没有

需要强调的一点:递归调用不应该无限的调用下去,必须在满足某种条件下结束递归调用

递归调用的两个阶段

  • 回溯:一层一层调用下去
  • 递推:满足某种结束条件,结束递归调用,然后一层一层返回
ata = [1, [2, [3, [4, [5]]]]]# 第一步:
for x in data:if type(x) is list:# 如果是列表,应该再循环,在判断,即重新运行本身的代码passelse:print(x)# 用递归
def f1(data):for x in data:if type(x) is list:# 如果是列表,应该再循环,在判断,即重新运行本身的代码f1(x)else:print(x)f1(data)

八、面向过程编程思想/范式

面向就是心中一直思考的意思

核心是“过程”二字,过程即流程,指的是做事的步骤,先什么,再什么

基于该思想编写程序就好比在设计一条流水线

  • 优点:复杂的问题流程化,进而简单化
  • 缺点:扩展性非常差,(比如流水线,牵一发而动全身,一个要改,全部要改)

程序的可扩展性极差,因为一套流水线或者流程就是用来解决一个问题,就好比生产汽水的流水线无法生产汽车一样,即便是能,也得是大改,而且改一个组件,与其相关的组件可能都需要修改,这就造成了连锁反应,而且这一问题会随着程序规模的增大而变得越发的糟糕。

注意:

  1. 不是所有的软件都需要频繁更迭,比如编写脚本
  2. 即便是一个软件需要频繁更迭,也不代表这个软件所有的组成部分都需要一起更迭
面向过程的程序设计一般用于那些功能一旦实现之后就很少需要改变的场景, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程去实现是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护, 那还是用面向对象最为方便。

九、匿名函数

对比使用def关键字创建的是有名字的函数,使用lambda关键字创建则是没有名字的函数,即匿名函数,语法如下

lambda 参数1,参数2,...: expression
# 1、定义
lambda x,y,z:x+y+z#等同于
def func(x,y,z):return x+y+z# 2、调用
# 方式一:
res=(lambda x,y,z:x+y+z)(1,2,3)# 方式二:
func=lambda x,y,z:x+y+z # “匿名”的本质就是要没有名字,所以此处为匿名函数指定名字是没有意义的
res=func(1,2,3)

匿名函数与有名函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放,所以匿名函数用于临时使用一次的场景,匿名函数通常与其他函数配合使用

十、 map、reduce、filter

函数map、reduce、filter都支持迭代器协议,用来处理可迭代对象,我们以一个可迭代对象array为例来介绍它们三个的用法

array=[1,2,3,4,5]

要求一:对array的每个元素做平方处理,可以使用map函数

map函数可以接收两个参数,一个是函数,另外一个是可迭代对象,具体用法如下

res=map(lambda x:x**2,array)
print(res)
print(list(res))

解析:map会依次迭代array,得到的值依次传给匿名函数(也可以是有名函数),而map函数得到的结果仍然是迭代器

要求二:对array进行合并操作,比如求和运算,这就用到了reduce函数

reduce函数可以接收三个参数,一个是函数,第二个是可迭代对象,第三个是初始值

# reduce在python2中是内置函数,在python3中则被集成到模块functools中,需要导入才能使用
from functools import reducearray=[1,2,3,4,5]
res=reduce(lambda x,y:x+y,array)
print(res)

解析:

  1. 没有初始值,reduce函数会先迭代一次array得到的值作为初始值,作为第一个值数传给x,然后继续迭代一次array得到的值作为第二个值传给y,运算的结果为3
  2. 将上一次reduce运算的结果作为第一个值传给x,然后迭代一次array得到的结果作为第二个值传给y,依次类推,知道迭代完array的所有元素,得到最终的结果15

也可以为reduce指定初始值

from functools import reducearray=[1,2,3,4,5]
res = reduce(lambda x,y:x+y,array,100)
print(res)

要求三:对array进行过滤操作,这就用到了filter函数,比如过滤出大于3的元素

array=[1,2,3,4,5]
res = filter(lambda x: x > 3, array)
print(list(res))

解析:filter函数会依次迭代array,得到的值依次传给匿名函数,如果匿名函数的返回值为真,则过滤出该元素,而filter函数得到的结果仍然是迭代器

提示:我们介绍map、filter、reduce只是为了带大家了解函数式编程的大致思想,在实际开发中,我们完全可以用列表生成式或者生成器表达式来实现三者的功能

13 Python函数进阶相关推荐

  1. python 函数进阶_Python学习入门基础:一篇文章搞定函数基础、函数进阶

    一.函数基础函数的快速体验 函数的基本使用 函数的参数 函数的返回值 函数的嵌套调用 在模块中定义函数私信小编001即可获取Python学习资料01. 函数的快速体验 1.1 快速体验 所谓函数,就是 ...

  2. 好好学python·函数进阶(递归函数,回调函数,闭包函数,匿名函数,迭代器)

    函数进阶 递归函数 回调函数 闭包函数 特点 匿名函数 lambda 表达式 迭代器 iter() next() 迭代器的取值方案 迭代器取值特点,取一个少一个,直到都取完,最后再获取就会报错 检测迭 ...

  3. Python — 函数进阶(2)

    文章目录 函数进阶(2) 可迭代对象 什么是可迭代对象 可迭代对象的意义 可迭代对象的使用 迭代器 什么是迭代器 迭代器的优势 迭代器的劣势 怎么使用迭代器 生成器 什么是生成器 怎么使用生成器 以函 ...

  4. Python函数进阶(11)

    函数进阶 函数参数类型 不可变数据类型和可变数据类型自加的区别 1. 判断gl_num和gl_list的值 命名空间 作用域 全局变量和局部变量 global 和nonlocal关键字 内置函数 1. ...

  5. python函数进阶小结_python之函数进阶

    1. 今日内容 1.1 函数的参数 *的魔性用法 函数形参最终顺序 1.2名称空间 全局名称空间,局部名称空间,内置名称空间 取值顺序与加载顺序 作用域 内置函数:globals() locals() ...

  6. 2.3.14 Python 函数进阶-生成器

    通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素 ...

  7. python 函数进阶_python之函数进阶

    1. 今日内容 1.1 函数的参数 *的魔性用法 函数形参最终顺序 1.2名称空间 全局名称空间,局部名称空间,内置名称空间 取值顺序与加载顺序 作用域 内置函数:globals() locals() ...

  8. python函数进阶小结_Python-进阶-functools模块小结

    文档 地址 functools.partial 作用: functools.partial 通过包装手法,允许我们 "重新定义" 函数签名 用一些默认参数包装一个可调用对象,返回结 ...

  9. 2.3.12 Python 函数进阶-装饰器

    代码运行期间动态增加功能的方式,称之为"装饰器"(Decorator) 本质上,decorator就是一个返回函数的高阶函数 所以,我们要定义一个能打印日志的decorator,可 ...

  10. Python函数进阶

    def eat(a,b,v,f,g): print(a,b,v,f,g) eat('方便面','包子','麻团','豆浆','咸菜') def eat(a,b,*args): # 聚合 打包 prin ...

最新文章

  1. python代码颜色不同_Python填充任意颜色,不同算法时间差异分析说明
  2. 有关迷宫的c语言程序的编写,3种C语言编写走迷宫的方法
  3. 医药计算机人员试题及答案,医药计算机应用试题.doc
  4. ROS 基础: 在同一个节点里订阅和发布消息
  5. 【题解】Inspection UVa 1440 LA 4597 NEERC 2009
  6. ubuntu安装PYQT4
  7. win10系统无法删除文件提示找不到该项目解决办法
  8. 计算机类核心期刊投稿的一些资料汇总
  9. c语言汉字utf8,C语言汉字gbk转utf-8
  10. 移动硬盘——显示盘符但打不开
  11. php日程提醒,php日程控件
  12. 学生用计算机怎么调,电脑怎么设置学生模式
  13. 计算机房通气换气次数,地下制冷机房,水泵房,配电房的排风量按多少换气次数计算...
  14. 求素数个数【C语言】
  15. springboot概述、自动转配原理、yaml语法、多环境配置及文件位置
  16. 在线电脑内存测试软件,内存占用测试_软件资讯软件评测-中关村在线
  17. group by使用
  18. JAVA基础6.52——多态的描述(2)
  19. 《创践——大学生创新创业实任务》 单元测试_ 笔记
  20. 处理VFS对象及标准函数--标准函数

热门文章

  1. 激光导航AGV-激光雷达安装要求
  2. SpringBoot + Vue 前后端分离的小案例
  3. 小米pro15拆机_实战小米笔记本PRO 15.6寸拆解 加装M.2海力士固态硬盘
  4. iphone6连接电脑后计算机不显示器,iPhone6怎么无故显示屏不亮了
  5. 51job简历如何导出pdf格式
  6. 利用lavarel框架实现Todos App
  7. 软件开发:关于园林绿化工中级理论知识题题库的软件内容
  8. Unity UI层级管理框架
  9. 是否要允许堵车“加塞”的帕累托最优、纳什均衡分析
  10. 做网站的定律原理和效应