Python程序设计现代方法(第2版) 课件 第6章 函数与模块_第1页
Python程序设计现代方法(第2版) 课件 第6章 函数与模块_第2页
Python程序设计现代方法(第2版) 课件 第6章 函数与模块_第3页
Python程序设计现代方法(第2版) 课件 第6章 函数与模块_第4页
Python程序设计现代方法(第2版) 课件 第6章 函数与模块_第5页
已阅读5页,还剩67页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章函数与模块《Python程序设计现代方法(第2版)》学习目标/Target

了解函数,能够说出函数的概念以及好处

掌握函数的定义与调用,能够正确地定义并调用函数

掌握函数参数的传递方式,能够通过多种方式给函数的参数传递数据掌握函数的返回值,能够根据需要使用return语句返回函数处理结果掌握变量作用域,能够说出全局变量和局部变量的特点学习目标/Target

掌握递归函数的使用,能够运用递归函数解决阶乘的问题

掌握匿名函数的使用,能够运用匿名函数简化简单函数的定义

掌握模块的导入与使用,能够通过不同语句导入模块并使用模块的内容

掌握模块的变量,能够归纳变量__all__和__name__的作用章节概述/Summary程序开发过程中,随着需要处理的问题变得越来越难,程序也会变得越来越长。冗长的程序牵扯的情况比较复杂,这不仅增加了阅读和理解的难度,也不利于后期对程序的维护与二次开发。函数和模块的出现便解决这些问题,它们为开发人员提供了丰富的工具和自由度,使得开发各种复杂的程序变得更加简单和高效。本章将详细介绍函数的相关知识,并简要介绍一些关于模块的知识。目录/Contents01函数概述函数的基础知识函数的参数传递0203函数的返回值04目录/Contents05变量作用域实例:智能聊天机器人函数的特殊形式0607模块08函数概述6.16.1函数概述通常,处理复杂问题的基本方法是“化繁为简,分而治之”,也就是说将复杂的问题分解成若干个足够小的问题,逐个解决这些小问题,最终达到解决大问题的目的。例如,把大象装进冰箱可分成三步,分别是打开冰箱门、把大象放进去、关上冰箱门。只要逐个解决上述的小问题,便能解决最初设定的大问题。同理,在设计程序时,可以先将程序拆解成若干个小功能,然后逐个实现这些小的功能。程序开发时,这些小功能可以使用函数来封装。6.1函数概述函数是一段有组织、可重复使用的、用来实现单一或相关联功能的代码段,通过函数名称进行调用。函数可以看作是一段有名字的子程序,可以在需要的地方使用函数名调用执行。6.1函数概述函数是一种功能抽象,它可以实现特定的功能,就像黑箱模型一样。黑箱模型是指所建立的模型只考虑输入与输出,而与过程、机理无关。现实生活中,许多实物应用了黑箱原理,比如洗衣机。使用者只需要了解洗衣机的使用方法,将洗衣粉和水放入洗衣机中,就可以得到洗干净的衣服。同样地,对于函数,外界不需要了解其内部的实现原理,只需要了解函数的输入输出方式即可使用。换言之,调用函数时以不同的参数作为输入,以执行函数后以函数的返回值作为输出。6.1函数概述函数大体可以划分为两类,一类是系统内置的函数,它们由Python标准库提供,例如,前面章节中学习的print()、input()、type()、int()等函数;另一类是自定义函数,即用户根据需求定义的具有特定功能的一段代码。自定义函数像一个具有某种特殊功能的容器——将多条语句组成一个有名称的代码段,以实现具体的功能。6.1函数概述使用函数的好处主要体现在以下几方面:提高代码的可读性和可维护性。将功能封装成函数,可以使代码更加模块化,易于理解和修改。减少代码的重复性。通过函数封装重复的功能,可以避免代码冗余,提高代码的复用性。提高程序的可扩展性。使用函数可以将不同的功能组合在一起,从而实现更复杂的功能。提高程序的可靠性。将功能封装成函数可以减少代码中的错误,降低程序出错的风险。提高程序的性能。通过函数封装重复的功能,可以减少代码执行的时间和空间复杂度,提高程序的性能。函数的基础知识6.26.2.1函数的定义Python使用def关键字定义函数,基本语法格式如下:关键字def:标志着函数的开始。函数名:函数的唯一标识,其命名方式遵循标识符的命名规则。参数列表:可以有零个、一个或多个参数,多个参数之间使用英文逗号分隔。根据参数的有无,函数分为有参函数和无参函数。冒号:用于标记函数体的开始。文档字符串:用于描述函数的功能,可以省略。函数体:函数每次调用时执行的代码,由一行或多行语句构成。return语句:标志着函数的结束,用于将函数的处理结果返回给函数调用者。若函数需要返回值,则使用return语句返货,否则return语句可以省略。def函数名([参数列表]):['''文档字符串''']

函数体 [return语句]6.2.1函数的定义定义函数时,函数参数列表中的参数是形式参数,简称为“形参”,形参用来接收调用函数时传入函数的参数。注意,形参只会在函数被调用的时候才分配内存空间,一旦调用结束就会即刻释放,因此,形参只有在函数内部有效。defmy_absolute(x):ifx>=0:print(x)else:print(-x)定义一个求绝对值的函数,示例如下:6.2.2函数的调用函数定义好之后不会立即执行,直到被程序调用时才会生效。调用函数的方式非常简单,一般形式如下:函数名([参数列表])例如,调用6.2.1中定义好的my_absolute()函数,代码如下:my_absolute(-10.0)以上形式的参数列表中的参数是实际参数,简称为“实参”,它们可以是常量、变量、表达式、函数等,这些实参会根据它们在函数定义中出现的顺序或名称与函数中的形参进行匹配,并在匹配成功后被传递给形参。6.2.2函数的调用程序在执行时,若遇到函数调用,会经历以下流程:程序在函数调用处暂停执行;将实参传入函数的形参;执行函数体中的语句;程序接收函数的返回值并继续执行。若函数没有返回值,则会省略接收返回值的步骤。6.2.2函数的调用下面以my_absolute()函数为例,为大家介绍函数的调用过程。假设定义和调用my_absolute()函数的完整代码如下:defmy_absolute(x):ifx>=0:print(x)else:print(-x)my_absolute(-10.0)print("---程序结束---")函数的参数传递6.36.3.1位置传递当调用函数时,默认情况下实参会按照位置顺序传递给对应的形参,即将第一个实参传递给第一个形参,第二个实参传递给第二个形参,以此类推。deftest_param(a,b,c):print(a,b,c)test_param(1,2,3)6.3.2关键字传递虽然位置传递的方式比较便捷,但是如果形参的数目过多,开发者很难记住每个形参的作用,这时可以通过关键字传递的方式给形参传值,这里的关键字就是形参的名称。当调用函数时,通过“形参名=实参”的形式将形参与实参关联,按照形参的名称进行参数传递,它允许实参和形参的顺序不一致。deftest_param(a,b,c):print(a,b,c)test_param(a=1,c=3,b=2)多学一招:仅限位置和权限关键字仅限位置,顾名思义就是调用函数时只能根据位置将实参传递给形参,不能再根据关键字将实参传递给形参。当定义函数时,只要在函数的形参前面明确使用符号/,那么/前面的形参需要严格遵守仅限位置的要求。deftest_param(a,b,/,c):#定义函数,部分参数遵守仅限位置的要求print(a,b,c)test_param(1,2,3)test_param(1,2,c=3)1.仅限位置多学一招:仅限位置和权限关键字仅限关键字,顾名思义就是调用函数时只能根据关键字将实参传递给形参,不能再根据位置将实参传递给形参。当定义函数时,只要在函数的形参前面明确使用符号*,那么符号*后面的形参需要严格遵守仅限关键字的要求。2.仅限关键字deftest_param(a,*,b,c):#定义函数,部分参数遵守仅限关键字的要求print(a,b,c)test_param(1,b=2,c=3)test_param(a=1,b=2,c=3)6.3.3默认值传递在定义函数时可以给每个形参指定默认值,基本形式为“形参名=默认值”,这样在调用时既可以给带有默认值的形参传递实参,以便重新为该形参赋值,也可以省略相应的实参,使用形参的默认值。deftest_param(a,b,c=6print(a,b,c)test_param(1,2,3)test_param(1,2)6.3.4包裹传递若函数在定义时无法确定接收多少个实参,那么可以在定义函数时给形参名称添加“*”或“**”。若一个形参名称前面加上“*”,它可以接收一个以元组形式包裹的多个实参。若一个形参名称前面加上“**”,它可以接收一个以字典形式包裹的多个实参。例如,定义一个形参为*args的函数,代码如下deftest_param(*args):#定义函数,该函数有一个加*的形参print(args)调用以上定义的test_param()函数可以传入多个实参,比如传入5个实参,代码如下:

test_param(1,2,3,4,5)6.3.4包裹传递例如,定义一个形参为**kwargs的函数,代码如下:deftest_param(**kwargs):#定义函数,该函数有一个加**的形参print(kwargs)调用以上定义的test_param()函数时可以传入多个实参,比如传入5个实参,代码如下:test_param(a=1,b=2,c=3,d=4,e=5)6.3.5解包裹传递在调用函数时,若函数接收的实参为元组或字典类型,可以使用“*”和“**”对实参解包裹,将实参拆分为多个值,并按照位置传递或关键字传递的方式将实参赋给形参。deftest_param(a,b,c):print(a,b,c)tuple_demo=(1,2,3)test_param(*tuple_demo)#调用函数,使用*对实参解包裹6.3.5解包裹传递下面再来看一下对字典解包裹的示例,代码如下:dict_demo={'a':1,'b':2,'c':3}test_param(**dict_demo)#调用函数,使用**对实参解包裹6.3.6混合传递前面介绍的几种参数传递的方式可以混合使用,但是在定义函数或调用函数时需要注意前后的顺序。在定义函数时,带默认值的形参必须位于普通形参(不带默认值或标识的形参)之后,带“**”标识的形参必须位于带“*”标识的形参之后。6.3.6混合传递当调用具有以上几种形参的函数时,需要遵循一定的规则:优先按照位置传递;其次按照关键字传递;再次按照默认值传递;最后按照包裹传递。6.3.6混合传递例如,定义一个函数,该函数包含多种形式的形参,具体代码如下:deftest_param(a,b,c=33,*args,**kwargs):print(a,b,c,args,kwargs)调用test_param()函数时,依次传入不同个数和形式的实参,具体代码如下:test_param(1,2)test_param(1,2,c=3)test_param(1,2,3,'a','b')test_param(1,2,3,'a','b',x=99)函数的返回值6.46.4函数的返回值函数中的return语句是可选项,它可以出现在函数体的任何位置,作用是结束当前函数,返回到函数被调用的位置继续执行程序,同时将函数处理的结果返回函数调用者。6.4函数的返回值下面编写一个函数,该函数用于判断键盘输入的字符串是否以大写字母开头,并返回判断结果,示例如下:defis_capital(words):iford("A")<=ord(words[0])<=ord("Z"):return'首字母是大写的'else:return'首字母不是大写的'result=is_capital("Python")#将函数返回的判断结果赋给变量print(result)6.4函数的返回值函数中的return语句可以返回多个值,这些值将以元组形式保存。例如,定义一个控制游戏角色移动的函数move(),使用return语句返回反应角色当前位置的nx和ny,代码如下:defmove(x,y,step):nx=x+stepny=y-stepreturnnx,ny#使用return语句返回多个值result=move(100,100,60)print(result)变量作用域6.56.5.1局部变量在函数内部定义的变量称为局部变量,局部变量只能在定义它的函数内部使用。局部变量的作用域仅限于定义它的函数范围内,同一个作用域内,不允许出现同名变量。deftest():count=0 #定义一个局部变量print(count) #函数内部访问局部变量test()print(count) #函数外部访问局部变量例如,定义一个包含局部变量count的函数test(),在函数的内部和外部分别访问这个局部变量count,代码如下:6.5.2全局变量全局变量是指在整个程序中都可以使用的变量,它们一般定义在函数外部,并且在整个程序运行期间占用存储单元。默认情况下,函数的内部只能访问全局变量,而不能修改全局变量的值。6.5.2全局变量count=10#定义一个全局变量deftest():count=11#函数内部尝试修改全局变量的值print(count)test()print(count)例如,定义的test()函数,完整代码如下:运行代码,结果如下所示:1110函数的内部并没有成功修改全局变量的值,而是定义了一个与全局变量同名的局部变量。6.5.2全局变量在函数内部若要修改全局变量的值,需要在修改之前使用关键字global进行声明,使声明的变量提升为全局变量,语法格式如下:global全局变量在test()函数中使用关键字global声明变量count,并对变量count进行修改,代码如下:count=10#全局变量deftest():globalcount#提升count为全局变量count=11#函数内修改count的值print(count)test()print(count)多学一招:LEGB法则LEGB是程序中搜索变量时所遵循的原则,该原则中的每个字母指代一种作用域,具体如下:L(local):局部作用域,例如局部变量和形参生效的区域。;E(enclosing):嵌套作用域,例如嵌套定义的外层函数中定义的变量生效的区域。G(global):全局作用域,例如全局变量生效的区域。B(built-in):内置作用域,例如,内置模块定义的变量生效的区域。Python在搜索变量时会按照“L-E-G-B”这个顺序依次在这四种区域中搜索:若搜索到变量则终止搜索,使用搜索到的变量;若搜索完L、E、G、B这四种区域仍无法找到变量,程序会出现报错信息。实例:智能聊天机器人6.66.6实例:智能聊天机器人近年来,智能聊天机器人在国内得到广泛应用,涵盖从企业客户服务到教育和医疗等领域,解决了人们日常生活中的问题,提供了更加便捷、高效、智能的服务。比如,科大讯飞推出的语音AI主播“小晴”,能够根据文本稿件模拟真人声音进行主播工作;深圳某职业学校推出的AI识别模拟考场程序——“AI超级智能考场监考系统”,可自动监测学生考试数据,为学生成绩考核提供便利;百度推出的智能聊天机器人“小度”能够自然流畅地与用户进行信息、服务、情感等多方面的交流。6.6实例:智能聊天机器人本实例要求实现一个简易智能聊天机器人——小智,用于帮助用户解答百科知识的问题,具体要求如下。(1)机器人默认会解答5个问题,这5个问题分别是诗仙是谁、中国第一个朝代、三十六计的第一计是什么、天府之国是中国的哪个地方、中国第一长河,答案分别是李白、夏朝、瞒天过海、四川、长江。(2)机器人有3项功能,分别是训练、对话和离开,若用户从键盘输入t,说明用户想训练机器人,此时机器人需要记录训练的新问题及答案;若用户从键盘输入c,说明用户想跟机器人对话,此时机器人需要回答用户提出的问题;若用户从键盘输入l,说明让机器人离开,此时机器人需要退出程序。6.6实例:智能聊天机器人本实例的实现思路可以分成以下步骤:(1)定义一个表示问题库变量,用于保存机器人能够回答的所有问题与答案。(2)定义两个全局变量,分别用于记录机器人初始的状态标记和工作标记。(3)定义一个用于训练机器人的函数,该函数包含两个参数,用于接收用户输入的新问题及其答案。6.6实例:智能聊天机器人本实例的实现思路可以分成以下步骤:(4)定义一个用于跟机器人对话的函数,该函数包含一个参数,用于接收用户提出的问题。(5)通过while语句控制用户使用机器人操作的完整流程。(6)在循环内部,通过input()函数接收用户输入的选项,通过if-elif-else语句判断选项是否为c、t、l或其他这几种情况,更新机器人的状态标记,并在各个分支下实现对应的功能。函数的特殊形式6.76.7.1匿名函数匿名函数是一类无须定义标识符的函数,它与普通函数一样可以在程序的任何位置使用,但是在定义时被严格限定为单一表达式。Python中使用lambda关键字定义匿名函数,它的语法格式如下:lambda<形式参数列表>:<表达式>6.7.1匿名函数与普通函数相比,匿名函数的体积更小,功能更单一,它只是一个为简单任务服务的对象,它们的主要区别如下:普通函数在定义时有名称,而匿名函数没有名称;普通函数的函数体中包含有多条语句,而匿名函数的函数体只能是一个表达式;普通函数可以实现比较复杂的功能,而匿名函数可实现的功能比较简单;普通函数能被其他程序使用,而匿名函数不能被其他程序使用。6.7.1匿名函数定义好的匿名函数不能直接使用,最好使用一个变量保存它,以便后期可以随时使用。例如,定义一个计算数值平方的匿名函数,并将其返回值赋值给一个变量:temp=lambdax:pow(x,2)#定义匿名函数,它返回的函数对象赋值给变量temp此时,变量temp可以作为匿名函数的临时名称来调用函数,示例如下:result=temp(10)print(result)6.7.2递归函数递归是指函数对自身的调用,它可以分为以下两个阶段:递推:递归本次的执行都基于上一次的运算结果。回溯:遇到终止条件时,则沿着递推往回一级一级地把值返回来。递归函数通常用于解决结构相似的问题,其基本的实现思路是将一个复杂的问题转化成若干个子问题,子问题的形式和结构与原问题相似,求出子问题的解之后根据递归关系可以获得原问题的解。6.7.2递归函数递归有两个基本要素:基例:子问题的最小规模,用于确定递归何时终止,也称为递归出口。递归模式:将复杂问题分解成若干子问题的基础结构,也称为递归体。递归函数的一般形式如下:def函数名称(参数列表): if基例:

rerun基例结果 else:

return递归体6.7.2递归函数递归最经典的应用就是阶乘,例如,求n的阶乘,数学中使用函数fact(n)表示:fact(n)=n!=1*2*3*...*(n-1)*n=fact(n-1)*n在程序中定义fact()函数实现阶乘计算,可以写成如下形式:deffact(n):ifn==1:#基例return1else:returnfact(n-1)*n#递归体6.7.2递归函数假设现在要求5的阶乘,则递归函数的整个执行过程如图所示。6.7.2递归函数计算斐波那契数列也是递归的一个经典应用。斐波那契数列又称黄金分割数列,这个数列从第三项开始,它的每一项都等于前两项的和。在数学上,斐波纳契数列以递推的方式定义,如下所示:F(1)=1,F(2)=1,F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)根据以上定义,斐波那契数列的前9项依次为:1、1、2、3、5、8、13、21、34。6.7.2递归函数斐波那契数列是以兔子繁殖为例子而引入,故又称为“兔子数列”。兔子繁殖的故事是这样的,一般兔子在出生两个月后就有繁殖能力,一对兔子每个月能生出一对小兔子来,如果所有的兔子都不死,那么一年以后一共有多少对兔子?6.7.2递归函数下面针对兔子繁殖的问题进行具体地分析:第一个月,兔子没有繁殖能力,此时兔子的总数量为1对;第二个月,兔子拥有了繁殖能力,生下一对小兔子,此时兔子的总数量为2对;第三个月,兔子又生下一对小兔子,而小兔子没有繁殖能力,此时兔子的总数量为3对;......依此类推,可以得到如下兔子数量统计表:经过月份0123456789101112幼崽对数101123581321345589成兔对数01123581321345589144总体对数11235813213455891442336.7.2递归函数使用代码实现计算兔子数列的函数,具体如下所示:defrabbit(month):

ifmonth==1:

return1

else:

returnrabbit(month-2)+rabbit(month-1)调用上述函数,可计算出经过一年以后,兔子的总数量为,代码如下:result=rabbit(12)print(result)模块6.86.8.1模块的导入和使用1.使用import语句导入模块import语句支持一次导入一个模块,也支持一次导入多个模块。使用import语句导入模块的语法格式如下。import模块1,模块2,…例如,导入Python中内置的模块random和time,代码如下:importtime #导入一个模块importrandom,time #导入多个模块6.8.1模块的导入和使用导入模块以后,可以通过“.”使用模块中的内容,包括全局变量、函数或类。使用模块内容的语法格式如下。模块名.变量名/函数名()/类名

例如,使用time模块中sleep()函数,示例如下:time.sleep(1)使用as关键字给模块起别名的语法格式如下。import模块名as别名1.使用import语句导入模块6.8.1模块的导入和使用使用import语句导入模块后,每次使用模块时都需要添加“模型名.”前缀,非常繁琐。为了减少这样的麻烦,Python提供了另外一种导入模块的语句from-import-。使用from-import-方式导入模块之后,无需添加前缀,可以像使用当前程序中的内容一样使用模块中的内容。使用from-import-语句导入模块的语法格式如下。from模块名import变量名/函数名/类名例如,导入time模块中的sleep()函数和time()函数,具体代码如下。fromtimeimportsleep,time2.使用from-import-语句导入模块6.8.1模块的导入和使用如果希望一次性导入模块中的全部内容,可以将from...import...语句中import后面的内容替换为通配符“*”。导入模块中全部内容的语法格式如下。from模块名import*例如,导入time模块中的全部内容,具体代码如下。fromtimeimport*2.使用from-import-语句导入模块6.8.1模块的导入和使用from-import-语句也支持为模块或模块中的内容起别名,其语法格式如下。from模块名import变量名/函数名/类名as别名例如,给time模块中的sleep()函数起别名为sl,具体代码如下。fromtimeimportsleepasslsl(1)#sl为sleep()函数的别名2.使用from-import-语句导入模块6.8.2模块的变量1.

__all__变量Python模块的开头通常会定义一个__all__变量,该变量的值实际上是一个列表,列表中包含的元素决定了在使用from-import*语句导入模块后可以使用模块的哪些内容。如果__all__中只包含模块中的部分内容,那么from-import*语句只会将__all__中包含的部分内容导入程序。6.8.2模块的变量下面创建两个模块calc.py和test.py,分步骤演示如何通过__all__变量限制导入这两个模块的内容,具体步骤如下。(1)创建模块calc.py,该模块中包含一个__all__变量和四个计算两个数的四则运算的函数,具体代码如下:#定义变量__all__,用于限制导入模块的内容__all__=["add","subtract"]defadd(a,b):returna+bdefsubtract(a,b):returna-bdefmultiply(a,b):returna*bdefdivide(a,b):if(b):returna/b

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论