python基础八(迭代器、生成器、生成式、递归、匿名函数、面向过程编程)
一 迭代器
1、什么是迭代器
迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而
继续的,单纯的重复并不是迭代
2、为何要有迭代器
迭代器是用来迭代取值的工具,而涉及到把多个值循环取出来的类
有:字符串、列表、元组、字典、集合、打开文件
l=['lq','zd','xiaobao']
i=0
while i<len(l):
print(l[i])
i+=1
上述迭代取值的方式只适用于有索引的数据类型:列表、字符串、元组
为了解决基于索引迭代器取值的局限性
python必须提供一种是能够不依赖于索引的取值方式,这就是迭代器
3、如何用迭代器
可迭代对象:但凡内置有__iter__方法的都称之为可迭代的对象
s = ''
s.__iter__()
l = []
l.__iter__()
t = ()
t.__iter__()
s = {1, 2, 3}
s.__iter__()
d = {'k1': 1, }
d.__iter__()
with open(r'a.txt', mode='rt', encoding='utf-8') as f:
f.__iter__()
pass
调用可迭代对象下的__iter__方法会将其装换成迭代器对象
d = {'a': 1, 'b': 2, 'c': 3}
d_iterator = d.__iter__()
print(d_iterator)
print(d_iterator.__next__())
print(d_iterator.__next__())
print(d_iterator.__next__())
print(d_iterator.__next__()) # 抛出异常stopiteration
# <dict_keyiterator object at 0x000002124897B7C0>
# a
# b
# c while True:
try:
print(d_iterator.__next__())
except StopIteration:
break print('--->') # 在一个迭代器取值取不干净的情况下,再对其取值取不到了
while True:
try:
print(d_iterator.__next__())
except StopIteration:
break
4、可迭代对象与迭代器对象详解
1) 可迭代对象("可以装换成迭代器的对象”):内置有__inter__方法对象
可迭代对象.__inter__():得到迭代器对象
2) 迭代器对象:内置有__next__方法并且内置有__iter__方法的对象
迭代器对象.__next__():得到迭代器的下一个值
迭代器对象.__iter__():得到迭代器的本身,说白了调了跟没调一个样子
5、可迭代对象和迭代器对象的区分
可迭代对象:字符串、列表、元组、集合、字典、文件对象
迭代器对象:文件对象
d = {'a': 1, 'b': 2, 'c': 3}
d_iterator = d.__iter__()
print(d_iterator.__next__())
# a
print(d_iterator is d_iterator.__iter__()) # True
6、for循环的工作原理:while循环叫条件循环,for循环可以叫迭代器循环
d = {'a': 1, 'b': 2, 'c': 3}
# 1、d.__iter__()得到一个迭代器对象
# 2、迭代器对象.__next__()拿到一个返回值,然后将返回值赋值给k
# 3、循环往复步骤2,直到到抛出StopIteration异常for循环会捕捉异常然后结束循环
for k in d:
print(k)
# a
# b
# c print(list("hello"))
# ['h', 'e', 'l', 'l', 'o']
7、迭代器优缺点总结
基于索引的迭代取值,所有迭代的状态都保存在了索引中,而基于迭代器实现迭代的方式不再需要索引,
所有迭代的状态就保存在迭代器中,然而这种处理方式优点与缺点并存:
优点:
1)、为序列和非序列类型提供了一种统一的迭代取值方式。
2)、惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用next来计算出一个值,就迭代器本身来说,
同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,如列表,需要把所有的元素都存放于内存中,
受内存大小的限制,可以存放的值的个数是有限的。
缺点:
1)、除非取尽,否则无法获取迭代器的长度
2)、只能取下一个值,不能回到开始,更像是‘一次性的’,迭代器产生后的唯一目标就是重复执行next方法直到值取尽,
否则就会停留在某个位置,等待下一次调用next;若是要再次迭代同个对象,你只能重新调用iter方法去创建一个新的迭代器对象,
如果有两个或者多个循环使用同一个迭代器,必然只会有一个循环能取到值。
二 生成器
如何得到自定义的迭代器:
在函数内一旦存在yield关键字,调用函数并不会执行函数体代码
会返回一个生成器对象,生成器即自定义的迭代器
def func():
print('第一次')
yield 1
print('第二次')
yield 2
print('第三次')
yield 3
print('第四次')
g = func()
print(g)
# <generator object func at 0x000001C516009B30>
# 生成器就是迭代器
g.__iter__()
g.__next__
# 会触发函数体代码的运行,然后遇到yield停下来,将yield后的值
# 当做本次调用的结果返回
res1 = g.__next__() # g.__next__等同于next(g) #next(g)方法后,才执行yield上面的代码体,res1才是yield后面的返回值
print(res1)
# 第一次
# 1
res2 = g.__next__()
print(res2)
# 第二次
# 2
# 例:放无穷个数
def func():
count = 0
while True:
count += 1
yield count
g = func()
print(next(g))
print(next(g))
list(g)
三 yield表达式
x=yield 返回值
1、
# 带有yield的函数运行流程,func调用,赋值给g,只是生成了生成器,没有触发函数代码体运行,g.send(),才触发函数代码体运行。
# g.send()赋值给res,res才是yield的返回值。
def func(name):
print('准备吃饭了:{}'.format(name))
while True:
# x拿到的是yield接受到的值
x = yield
print('今天吃:{}'.format(x))
g = func('xiaobao')
g.send(None) # 等同于next(g),触发yield上面的代码运行。
g.send('包子')
g.send('油条')
g.send('排骨')
# 准备吃饭了:xiaobao
# 今天吃:包子
# 今天吃:油条
# 今天吃:排骨
2、综合应用
def func(name):
food_list = []
print('准备吃饭了:{}'.format(name))
while True:
# x拿到的是yield接受到的值
x = yield food_list
print('今天吃:{}'.format(x))
food_list.append(x)
g = func('xiaobao')
res1 = g.send(None) # 等同于next(g),触发yield上面的代码运行。
print(res1)
res2 = g.send('包子')
print(res2)
res3 = g.send('油条')
print(res3)
res4 = g.send('排骨')
print(res4)
'''
准备吃饭了:xiaobao
[]
今天吃:包子
['包子']
今天吃:油条
['包子', '油条']
今天吃:排骨
['包子', '油条', '排骨']
'''
四 生成式
1、列表生成式
列表生成式是python为我们提供的一种简化代码的解决方案,用来快速生成列表,语法如下(就是for循环加l.append()的简化)
'''
[expression for item1 in iterable1 if condition1
for item2 in iterable2 if condition2
...
for itemN in iterableN if conditionN
]
#类似于
res=[]
for item1 in iterable1:
if condition1:
for item2 in iterable2:
if condition2
...
for itemN in iterableN:
if conditionN:
res.append(expression)
'''
# 列表生成式案例
l = ['xiaobao_', 'lq_', 'zd']
# 把所有小字母全变成大写
new_l = [item.upper() for item in l]
print(new_l)
# ['XIAOBAO_', 'LQ_', 'ZD']
# 把所有的名字去掉后缀_
new_l = [item.replace('_', '') for item in l if True] # 可以不用加if True
print(new_l)
# ['xiaobao', 'lq', 'zd']
2、字典生成式
items = [('xiaobao', 6), ('zd', 32), ('lq', 35), ('lr', 40)]
dic = {k: v for k, v in items if k != "lr"} # 解压赋值
print(dic)
3、集合生成式
4、生成器表达式
g = (i for i in range(10) if i > 2) # 没有元组生成器,元组不可改,没有.append()
print(g, type(g)) # !!!!!!!强调!!!!! 此刻g内部一个值没有(老母鸡,还没有下蛋),需要next(g),才产值。
for i in g:
print(i)
应用:统计day19中笔记中字符个数
# 方法一:
with open(r'笔记.txt', mode='r', encoding='utf-8') as f:
res = 0
for line in f:
# print(len(line))
res += len(line)
print(res)
# 577
# 方法二
with open(r'笔记.txt', mode='r', encoding='utf-8') as f:
res = sum([len(line) for line in f]) # sum()里面需要一个可迭代对象,方法二是列表
print(res)
# 577
# 方法三(效率最高)
with open(r'笔记.txt', mode='r', encoding='utf-8') as f:
# res=sum((len(line) for line in f )) # sum()里面需要一个可迭代对象,方法三是生成器
res = sum(len(line) for line in f) # 简化,sum()是触发了next()了的,生成器才产值
print(res)
# 577
print(len(line) for line in f) # <generator object <genexpr> at 0x000001BEFA49F510>
四 递归函数
1、函数递归调用:是函数嵌套调用的一种特殊形式
具体是指:
在调用一个函数的过程中又直接或者间接的调用本身
def f1():
print('from f1')
f1()
f1()
# 在调用f1的过程中,又调用f2,而在调用f2的过程中又调用f1,这就是间接调用函数f1本身
def f1():
print('from f1')
f2()
def f2():
print('from f2')
f1()
f1()
从上图可以看出,两种情况下的递归调用都是一个无限循环的过程,但在python对函数的递归调用的深度做了限制,
因而并不会像大家所想的那样进入无限循环,会抛出异常,要避免出现这种情况,就必须让递归调用在满足某个特定条件下终止。
1)可以使用sys.getrecursionlimit()去查看递归深度,默认值为1000,虽然可以使用
sys.setrecursionlimit()去设定该值,但仍受限于主机操作系统栈大小的限制
2)python不是一门函数式编程语言,无法对递归进行尾递归优化。
# 一段代码的循环运行的方案有两种
# 方式一:while、for循环
while True:
print(1111)
print(2222) # 方式二:递归的本质就是循环:
def f1():
print(111)
print(222)
f1()
f1()
2、需要强调的一点是:
递归调用不应该无限的调用下去,必须在满足某种条件结束递归
def func(n):
if n == 10:
return
print(n)
n += 1
func(n)
func(0)
3、递归的两个阶段
回溯:一层一层调用下去
递推:满足某种结束条件,结束递归调用,然后一层一层返回
# 例:问了五个人,第五的一个人说收入比第四的一个人高1000元,第一个人的收入3000元
def salary(n):
if n == 1:
return 3000
return salary(n - 1) + 1000
res = salary(3)
print(res)
# 5000
4、递归的应用
l = [[1, 2], 3, [4, [5, [6, 7]]]]
def foo(items):
for i in items: # for循环相当于自带了一个return
if type(i) is list:
# 如果是列表,应该再循环、再判断,即重新运行本身的代码
foo(i)
else:
print(i, end=' ')
foo(l) # 打印结果1 2 3 4 5 6 7
使用递归,我们只需要分析出要重复执行的代码逻辑,然后提取进入下一次递归调用的条件或者说递归结束的条件即可,代码实现起来简洁清晰
五 算法之二分法
算法:是高效解决问题的方法
需求:有一个按照从小到大顺序排列的数字列表
需要从该数字列表中找到我们想要的那个一个数字
如何做更高效
nums = [1, 2, 3, 5, 7, 22, 33, 34]
find_num = 7 # 方案一:整体遍历效率太低
for num in nums:
if num == find_num:
print('find it')
break # 方案二:二分法
# 找中间值mid_num
nums = [1, 2, 3, 5, 7, 22, 33, 34]
def binary_num(find_num, l):
print(l) mid_index = len(l) // 2
if len(l) == 0:
print('num not in list')
return
if find_num > l[mid_index]:
# 接下来查找列表右半部分
# 列表1=列表切右半部分
l = l[mid_index + 1:]
binary_num(find_num, l)
elif find_num < l[mid_index]:
# 接下来查找列表左半部分
l = l[:mid_index]
binary_num(find_num, l)
else:
print('find it')
binary_num(33, nums)
六 匿名函数
1、def用于定义有名函数
# func=函数的内存地址
def func(x, y):
return x + y
2、lamdab用于定义匿名函数
lambda x, y: x + y # x+y前的return省略
print(func) # <function func at 0x000001D758E27430>
print(lambda x, y: x + y) # <function <lambda> at 0x000001D758E271F0>
3、调用匿名函数
# 方式一:
(lambda x, y: x + y)(1, 2) # 调用,内存地址的调用
res = (lambda x, y: x + y)(1, 2) # 返回值
print(res)
# 3 # 方式二:
func = lambda x, y: x + y # “匿名”的本质就是要没有名字,所以此处为匿名函数指定名字是没有意义的
res = func(1, 2)
print(res)
# 3
4、匿名用于临时调用一次的场景:更多的是将匿名与其他函数配合使用
匿名函数与有名函数有相同的作用域,但是匿名意味着引用计数为0,使用一次就释放(垃圾回收机制),
所以匿名函数用于临时使用一次的场景,匿名函数通常与其他函数配合使用。
5、匿名函数使用
salaries = {
'siry': 3000,
'tom': 7000,
'lili': 10000,
'jack': 2000
} # 要想取得薪水的最大值和最小值,我们可以使用内置函数max和min def func(k):
return salaries[k]
# 函数max会迭代字典salaries,每取出一个“人名”就会当做参数传给指定的匿名函数,然后将匿名函数的返回值当做比较依据,
# 最终返回薪资最高的那个人的名字 res = max(salaries, key=func) # 返回值=func('siry')
print(res) # 用匿名函数替换
res = max(salaries, key=lambda k: salaries[k]) # max(salaries,key=lambda k:salaries[k],reverse=True),排序反过来。
print(res)
# lili
res = min(salaries, key=lambda k: salaries[k])
print(res)
# jack
# -------sorted
# 同理,我们直接对字典进行排序,默认也是按照字典的键去排序的
res = sorted(salaries)
print(res)
# ['jack', 'lili', 'siry', 'tom'] # 按值排序,按照值得从小到大,得到一个键的列表
res = sorted(salaries, key=lambda k: salaries[k])
print(res)
# ['jack', 'siry', 'tom', 'lili']
# ------函数map
array = [1, 2, 3, 4, 5]
res = map(lambda x: x ** 2, array)
# map会依次迭代array,得到的值依次传给匿名函数(也可以是有名函数),而map函数得到的结果仍然是迭代器。
print(res)
# <map object at 0x1033f45f8>
print(list(res)) # 使用list可以依次迭代res,取得的值作为列表元素
# [1, 4, 9, 16, 25]
# ------函数array
对array进行合并操作,比如求和运算,这就用到了reduce函数reduce函数可以接收三个参数,一个是函数,
第二个是可迭代对象,第三个是初始值# reduce在python2中是内置函数,在python3中则被集成到模块functools中,需要导入才能使用
>>> from functools import reduce
>>> res=reduce(lambda x,y:x+y,array)
>>> res
15解析:1 没有初始值,reduce函数会先迭代一次array得到的值作为初始值,
作为第一个值数传给x,然后继续迭代一次array得到的值作为第二个值传给y,
运算的结果为32 将上一次reduce运算的结果作为第一个值传给x,然后迭代一次array得到的结果作为第二个值传给y,
依次类推,知道迭代完array的所有元素,得到最终的结果15也可以为reduce指定初始值
>>> res=reduce(lambda x,y:x+y,array,100)
>>> res
115要求三:对array进行过滤操作,这就用到了filter函数,比如过滤出大于3的元素
>>> res=filter(lambda x:x>3,array)
解析:filter函数会依次迭代array,得到的值依次传给匿名函数,如果匿名函数的返回值为真,则过滤出该元素,而filter函数得到的结果仍然是迭代器。
>>> list(res)
[4, 5] 提示:我们介绍map、filter、reduce只是为了带大家了解函数式编程的大致思想,
在实际开发中,我们完全可以用列表生成式或者生成器表达式来实现三者的功能。
七 面向过程编程
编程思想/范式
面向过程的编程思想:
核心是“过程”二字,过程既流程,指的是做事的步骤:先什么,再什么,后干什么
基于该思想编写程序就好比在设计一条流水线
优点:复杂的问题流程化、进而简单化
缺点:扩展性非常差
面向过程的编程思想应用场景解析:
1、不是所有的软件都需要频繁更迭:比如编写脚本
2、即便是一个软件需要频繁更迭,也并代表这个软件所有的组成部分都是需要一起更迭
python基础八(迭代器、生成器、生成式、递归、匿名函数、面向过程编程)的更多相关文章
- Python入门之三元表达式\列表推导式\生成器表达式\递归匿名函数\内置函数
本章目录: 一.三元表达式.列表推导式.生成器表达式 二.递归调用和二分法 三.匿名函数 四.内置函数 ================================================ ...
- python基础6 迭代器 生成器
可迭代的:内部含有__iter__方法的数据类型叫可迭代的,也叫迭代对象实现了迭代协议的对象 运用dir()方法来测试一个数据类型是不是可迭代的的. 迭代器协议是指:对象需要提供next方法,它要么返 ...
- python基础——10(三元运算符、匿名函数)
一.三元运算符 本质是if--else--的语法糖 前提:简化if--else--的结构,且两个分支有且只有一条语句 案例: a = 20 b = 30 res = a if a > b els ...
- python基础知识07-函数作用域和匿名函数
1.匿名函数 list(filter(lamda a:a>3,[1,2,3,4,5])) 一般和过滤器一起使用 2.函数的作用域 a = 123 def test(): a = 666 a = ...
- python基础(补充):lambda匿名函数,用了的,都说好!
lambda函数又叫做"匿名函数".当你完成一件小工作时,直接使用该函数可以让你的工作得心应手. lambda函数介绍 在Python中,定义函数使用的是def关键字,但是通过la ...
- python基础(9)-迭代器&生成器函数&生成器进阶&推导式
迭代器 可迭代协议和迭代器协议 可迭代协议 只要含有__iter__方法的对象都是可迭代的 迭代器协议 内部含有__next__和__iter__方法的就是迭代器 关系 1.可以被for循环的都是可迭 ...
- (转)python基础之迭代器协议和生成器(一)
一 递归和迭代 二 什么是迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前 ...
- Python基础知识总结笔记(四)函数
Python基础知识总结笔记(四)函数python中的函数函数中的参数变量作用域偏函数PFA递归函数高阶函数BIFs中的高阶函数匿名函数lambda闭包Closure装饰器Decorator函数式编程 ...
- python基础(八)生成器,迭代器,装饰器,递归
生成器 在函数中使用yield关键字就会将一个普通的函数变成一个生成器(generator),普通的函数只能使用return来退出函数,而不执行return之后的代码.而生成器可以使用调用一个next ...
- python基础语法9 生成器,面向对象编程思想,三元表达式,列表生成式,生成器表达式(生成式),匿名函数,内置函数
生成器 1.什么是生成器? 生成的工具. 生成器是一个 "自定义" 的迭代器, 本质上是一个迭代器. 2.如何实现生成器 但凡在函数内部定义了的yield, 调用函数时,函数体代码 ...
随机推荐
- .NET Core开发实战(第34课:MediatR:轻松实现命令查询职责分离模式(CQRS))--学习笔记(下)
34 | MediatR:轻松实现命令查询职责分离模式(CQRS) 实际上我们在定义我的查询的时候,也可以这样定义,例如我们定义一个 MyOrderQuery,把订单的所有名称都输出出去 namesp ...
- 剑指Offer07 重建二叉树
剑指 Offer 07. 重建二叉树 前置概念: 前序:访问根节点,先序遍历左子树,先序遍历右子树: 中序:中序遍历左子树,访问根节点,中序遍历右子树: 后序:后序遍历左子树,后序遍历右子树,访问根节 ...
- NC16591 [NOIP2010]关押罪犯
题目链接 题目 题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气 ...
- gif 制作
gif 制作 博文中使用 gif 有时比纯粹的图片更明了.比如展示"墨刀"中的动画效果: 录制视频 首先利用录制视频,例如使用在线录制工具 vizard. Tip:需要花费2分钟手 ...
- CF-928(已更新:B C E)
CF-928 排名四千多,目前为止排名最高的一场~ E题我赛时基本上是猜的结论(但是也推了快一小时才想到有这个可能性),因此目前只能放个码在这(⊙﹏⊙) D的话问了学长思路,正在补了0-^-0 --但 ...
- spring boot中配置网页语言国际化
项目地址:https://gitee.com/indexman/spring_boot_in_action 开发步骤 1.编写国际化配置文件 场景是给登录页面 login.html添加国际化支持. 2 ...
- Postman文件数据导入导出
https://zhuanlan.zhihu.com/p/535757471?utm_id=0
- pycharm中自定义函数补全
在 PyCharm 中,你可以通过以下步骤实现这一目标: 打开 PyCharm,点击顶部菜单的 "File"(文件) -> "Settings"(设置). ...
- 【Java复健指南07】OOP中级02-重写与多态思想
前情提要:https://www.cnblogs.com/DAYceng/category/2227185.html 重写 注意事项和使用细节 方法重写也叫方法覆法,需要满足下面的条件 1.子类的方法 ...
- 【LeetCode二叉树#02】二叉树层序遍历(广度优先搜索),十合一专题
二叉树层序遍历(广度优先搜索) 102 二叉树的层序遍历 力扣题目链接(opens new window) 给你一个二叉树,请你返回其按 层序遍历 得到的节点值. (即逐层地,从左到右访问所有节点). ...