好程序员Python教程系列之递归函数与匿名函数调用
好程序员Python教程系列递归函数与匿名函数调用,函数是Python技术学习中重要的一个环节,深入掌握该阶段的知识内容,对于Python技术能力的提升非常有帮助,这里就针对递归函数与匿名函数两种函数调用进行系统的介绍分析。
一. 递归函数
a) 引言:在一个函数中自己调用自己会怎么样呢?会陷入无限的调用循环。为了解决该问题就需要使用递归。
b) 应用:
i. 案例分析:编写一个函数,该函数接收一个整数n,然后计算输出n的阶乘。
1. 首先定义一个一个函数def factorial(n),该函数应该怎么实现呢?我们知道计算n的阶乘有如下规律:n!=n[(n-1)[n-2]…1]=n(n-1)!
2. 函数实现步骤可以是:
def factorial(n):
1.计算(n-1)的阶乘
2.返回step1的结果值*n
要完成第一步的事情,就是要计算(n-1)!。由于我们这个函数是计算n!,因此第一步也可以理解为,以n-1为参数,调用factorial函数。代码就会变成:
def factorial(n):
1.factorial(n-1)
2.返回step1的结果值*n
在该代码中,出现了在factorial函数中调用factorial函数的情况。出现了函数的递归。为了完善上述代码,可以将代码中的第二部也翻译成代码:
def factorial(n):
1. int result=factorial(n-1)
2. return result*n
但是问题也出现了,加入n=3,在fac(3)的内部会调用fac(2),在fac(2)中会调用fac(1),在fac(1)中会调用fac(0)-》fac(-1)……因此我们需要规定一个循环调用结束的条件。在当前程序中当参数n的值为1时,则计算1的阶乘,到这一步就没有必要继续递归下去的必要了,因此n=1是,应当直接返回。
def factorial(n):
if(n==1):
return 1
int result=factorial(n-1)
return result*n
二. 匿名函数
a) 引言:当我们在创建函数的时,有的时候不需要显示的定义函数,直接传入匿名函数会更加的方便,这会省去我们挖空心思为函数命名的麻烦,也能少些不少的代码,很多编程语言都提供匿名函数这种特性。匿名函数用好了,会起到画龙点睛的效果,没用好就容易画虎不成反类犬,
b) 在Python中使用lambda关键字来创建匿名函数。所谓匿名,即不再使用def这种标准形式定义函数,需要注意的有:
i. lambda是一个表达式而不是一个代码块
ii. 仅仅能在lambda表达式中封装有限的逻辑
iii. Lambda函数拥有自己的命名空间
c) 语法结构:lambda 参数:表达式 例如 lambda x:x*x, 冒号前的x表示的是参数,后面的表示函数的执行代码,,它相当于下面的函数:
Def f(x): return x*x
d) 注意:
i. 匿名函数只能有一个表达式
ii. 不用也不能写return语句,表达式的结果就是返回值
iii. 匿名函数也是一个函数对象,可以将其赋值给一个变量,然后通过变量来调用该函数。f=lambda x:x*x f(6)
三. 推导式:是一种独特的推导式语法,可帮我们在某些场合写出比较精简炫酷的代码。但是没有它,也不会有太多的影响。
a) 分类:
i. 列表推导式
ii. 字典推导式
iii. 集合推导式
iv. 元组推导式?
b) 列表推导式:是一种快速生成列表的方式,其形式使用方括号括起来的一段语句。
i. 案例:lis=[xx for x in range(1,10) ] 首先执行for循环,对于每一个x带入xx中进行运算,将运算的结果值逐一添加到一个新的列表内(x*x的式子中使用的变量必须为for中的x)。尤其可见,列表推导式为我们提供了一种在一行内实现较为复杂逻辑的生成列表的方法。其核心语法就是用中括号将生成的逻辑封装起来。
ii. 案例:[x*x for x in range(1,11) if x%2==0] 通过增加if语句对x进行过滤
iii. 案例:dic={“k1”:”v1”,”k2”:”v2”} a=[k+”:”+v for k,v in dic.items()]
c) 字典推导式:列表推导式使用的是中括号,那么如果使用大括号则可以制造字典推导式
i. 案例:dic={x:x2 for x in(2,4,6)} x:x2中间的冒号左边表示key右边表示value
ii. 案例:也可以添加if子句
d) 集合推导式:大括号除了可以用作字典推导式还可以用作集合推导式,注意两者差别。
i. 案例:a={x for x in “abcdefg” if x not in “abc”}
e) 元组推导式:那是用小括号的是不是元组推导式呢?no。在python中使用小括号的被叫做生成器的语法,在python中没有元组推导式。
i. 如果想通过上述类似的方法生成元组,需要显示调用元组的类型转换函数tuple。t=tuple(x for x in range(10))
f) 面试题:
result = [lambda x: x + i for i in range(10)]
print(result0)
答案是19,并且result0~9的结果都是19。这是因为函数具有调用时才查找变量的特性。在你没调用它之前,它不会保存也不关心它内部变量的具体值。只有等到你调用它的时候,它才逐一去找这些变量的具体值。这里的result[0]被调用的时候,变量i已经循环完毕,变成9了,而不是想象中的动态0-9值。
那如果不想要这样的结果,想要i是循环的值怎么办?不要直接引用上层变量,把变量直接传进来。
result = [lambda x, i=i: x + i for i in range(10)]
print(result0)
四. 迭代器
a) 迭代:通过for循环遍历对象的每一个元素的过程。For可以遍历任何可迭代的对象。
b) 可迭代对象类型:list/tuple/string/dict/set/bytes。可以通过collections模块的Iterable类型来判断一个对象是否可迭代:
from collections import Iterable
isinstance('abc', Iterable) # str是否可迭代
c) 迭代器:是一种可以被遍历的对象。特点如下:
i. 能调用next()函数。
ii. 使用iter()函数创建迭代器对象
iii. 迭代器对象从集合的第一个元素开始访问,直到所有元素被访问结束
iv. 只能往后遍历,不能回溯
v. 案例:
>>> lis=[1,2,3,4]
>>> it = iter(lis) # 使用Python内置的iter()方法创建迭代器对象
>>> next(it) # 使用next()方法获取迭代器的下一个元素
1
>>> next(it)
2
>>> next(it)
3
>>> next(it)
4
>>> next(it) # 当后面没有元素可以next的时候,弹出错误
或者使用for循环遍历迭代器:
lis = [1,2,3,4]
it = iter(lis) # 创建迭代器对象
for x in it: # 使用for循环遍历迭代对象
print (x, end=" ")
迭代器的作用:除了可迭代的类型可以进行迭代外,在开发中也会遇到一些自定义的类型也有迭代的需求,即将自定义类型定义成迭代器类型即可(需要在类里实现__iter__()和__next__()方法,可供next和iter函数调用该对象)。for循环本质上就是通过不断调用next()函数实现的
def iter(obj):
return obj.__iter__()
def next(obj):
return obj.__next__()
自定义迭代器类:
import random
class demo_iterator(object):
def __next__(self):
v = random.randint(0,10)
if v < 5:
raise StopIteration()
else:
return v
def __iter__(self):
return demo_iterator()
迭代作用:可以把这个元素流看做是一个有序序列,但却不能提前知道序列的长度,只能不断通过next()函数得到下一个元素,所以迭代器可以节省内存和空间。
五. 生成器
a) 引言:有时候,序列或集合内的元素的个数非常巨大,如果全制造出来并放入内存,对计算机的压力是非常大的。比如,假设需要获取一个10**20次方如此巨大的数据序列,把每一个数都生成出来,并放在一个内存的列表内,这是粗暴的方式,有如此大的内存么?如果元素可以按照某种算法推算出来,需要就计算到哪个,就可以在循环的过程中不断推算出后续的元素,而不必创建完整的元素集合,从而节省大量的空间。在Python中,这种一边循环一边计算出元素的机制,称为生成器:generator。
b) 语法格式:类似推导式,使用小括号
c) 案例:
>>> g = (x * x for x in range(1, 4))
>>> g
at 0x1022ef630>
可以通过next()函数获得generator的下一个返回值,这点和迭代器非常相似:
>>> next(g)
1
但更多情况下,我们使用for循环。
for i in g:
print(i)
d) 关键字yield:
1. 用法:使用yield返回的函数会变成一个生成器。在调用生成器的过程中,每次遇到yield时,函数会暂停并保存当前所有的运行信息,返回yeild值。并在下一次运行next方法时从当前位置继续执行。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
视频直播源码优化的正确姿势
视频直播行业用户观看体验是第一位,视频直播源码在开发前通常会对各种常见问题做出预备方案,通过提前预防的方式保证用户们的直播观看体验。视频直播源码常见问题的解决方案一般都由开发团队提供,或运营商自己的开发团队保证直播平台、系统定期的维护。平台最容易出现问题的时间段在晚上,晚上平台用户观看人数多,对服务器、系统造成的压力都比较大,很容易出现视频传输卡顿、延迟高等问题。 优化方案:1.在主播端和用户端交互时会经常性的产生时间延迟问题,缩短这个时间延迟才是解决问题的关键。针对这一问题,团队更推荐使用CDN服务器传输视频流,通过CDN广泛分布的节点,缩短用户与服务器之间的物理距离,再用网速弥补网络传输问题,实现最终的秒开、延迟低直播。2.卡顿问题也是视频直播中常见的问题,卡顿是因为视频播放过程中出现了画面滞帧现象,视频关键帧信息无法及时传递,造成最终的卡顿现象。信息传递过程中出现网络堵塞也会影响关键帧传递,解决卡顿的方法很简单,减少网络抖动现象、更换终端设备的解码性能,最终就能达到降低甚至消除卡顿的效果。 3.影响视频直播源码效果的因素还包括手机的系统。iOS端开发较简单,系统一致好解决。但An...
- 下一篇
好程序员Python教程系列-第6讲:循环结构
好程序员Python教程系列-第6讲:循环结构,应用场景:我们在写程序的时候,一定会遇到需要重复执行某条或某些指令的场景。例如用程序控制机器人踢足球,如果机器人持球而且还没有进入射门范围,那么我们就要一直发出让机器人向球门方向移动的指令。在这个场景中,让机器人向球门方向移动就是一个需要重复的动作,当然这里还会用到上一课讲的分支结构来判断机器人是否持球以及是否进入射门范围。再举一个简单的例子,如果要实现每隔1秒中在屏幕上打印一次“hello, world”并持续打印一个小时,我们肯定不能够直接把print('hello, world')这句代码写3600遍,这里同样需要循环结构。循环结构就是程序中控制某条或某些指令重复执行的结构。在Python中构造循环结构有两种做法,一种是for-in循环,一种是while循环。for-in循环如果明确的知道循环执行的次数,我们推荐使用for-in循环,例如计算1到100的和,即。"""用for循环实现1~100求和 Version: 0.1Author: 骆昊"""total = 0for x in range(1, 101): total += x...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Mario游戏-低调大师作品
- CentOS关闭SELinux安全模块
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,CentOS7官方镜像安装Oracle11G