资源简介 单元5 函数应用与模块化程序设计课程名称 Python程序设计任务驱动式教程 章名 函数应用与模块化程序设计教学内容 函数应用与模块化程序设计 课时 6项目性质 □演示性 □验证性 □设计性 √综合性授课班级 授课日期 授课地点教学目标 了解随机数函数和下载与安装第三方模块的方法 掌握Python数学函数的应用 掌握Python函数的定义与调用 掌握Python函数参数 掌握函数变量的作用域 掌握Python的模块创建与导入 掌握Python中创建与使用包教学内容 Python数学函数的应用 Python函数的定义与调用 Python函数参数 函数变量的作用域 Python的模块创建与导入 Python中创建与使用包教学重点 Python函数的定义与调用、Python函数参数、Python的模块创建与导入教学难点 Python函数的定义与调用、Python函数参数、Python的模块创建与导入教学准备 装有Python的计算机 教学课件PPT 教材:《Python程序设计任务驱动式教程(微课版)》作业设计21教学过程教学环节 教学内容与过程 (教学内容、教学方法、组织形式、教学手段)课前组织 做好上课前的各项准备工作(打开计算机、打开课件、打开软件、打开授课计划、教案等),吸引学生注意力。课程说明 【课前说明】 分别从随机数函数和下载与安装第三方模块等知识点进行初步的了解。 【目的】 使学生从了解本节课的学习目标、学习重点、考评方式等方面明确课程学习的要求和目标。课程内容描述 5.1 Python数学函数的应用 5.1.1 Python数学常量 Python数学常量主要包括数学常量pi(圆周率,一般以π来表示)和数学常量e(自然常数)。 5.1.2 Python常用数学运算函数 Python常用数学运算函数如表所示。 Python常用数学运算函数 序号函数功能描述与返回值1abs(x)返回数值的绝对值,例如abs(-10)返回102ceil(x)返回数值的上入整数,例如math.ceil(4.1)返回53cmp(x,y)如果xy返回14exp(x)返回e的x次幂,例如math.exp(1)返回2.7182818284590455fabs(x)返回数值的绝对值,例如math.fabs(-10)返回10.06floor(x)返回数值的下舍整数,例如math.floor(4.9)返回47log(x)如math.log(math.e)返回1.0,math.log(100,10)返回2.08log10(x)返回以10为基数的x的对数,例如math.log10(100)返回2.09max(x1,x2,…)返回给定参数的最大值,参数可以为序列10min(x1,x2,…)返回给定参数的最小值,参数可以为序列11modf(x)返回x的整数部分与小数部分,两部分的数值符号与x相同,整数部分以浮点数表示12pow(x,y)x**y运算后的值,即返回x的y次幂13round(x[,n])返回浮点数x的四舍五入值,例如给出n值,则代表舍入到小数点后的位数14sqrt(x)返回数值x的平方根15acos(x)返回x的反余弦弧度值16asin(x)返回x的反正弦弧度值17atan(x)返回x的反正切弧度值18atan2(y,x)返回给定的x和y坐标值的反正切值19cos(x)返回x的弧度的余弦值20hypot(x,y)返回欧几里得范数sqrt(x*x+y*y)21sin(x)返回x的弧度的正弦值22tan(x)返回x的弧度的正切值23degrees(x)将弧度转换为角度,例如degrees(math.pi/2),返回90.024radians(x)将角度转换为弧度【任务5-1】编写程序绘制爱心 【任务描述】 (1)在PyCharm集成开发环境中创建项目Unit05。 (2)在项目Unit05中创建Python程序文件5-1.py。 (3)编写程序绘制爱心。 【任务实施】 1.创建PyCharm项目Unit05 成功启动PyCharm后,在指定位置“D:\PycharmProject\”创建PyCharm项目Unit05。 2.使用pip命令下载与安装第三方模块 在PyCharm项目Unit05中新建Python程序文件5-1.py,同时PyCharm主窗口显示程序文件5-1.py的代码编辑窗口,在该程序文件的代码编辑窗口自动添加了模板内容。 3.在PyCharm中自动导入相关库或模块 本单元的【任务5-1】中需要使用“matplotlib”“numpy”模块,为了保证程序能正常运行,必须先导入相关模块,这里介绍使用快捷键快速导入所需模块的操作方法。 在PyCharm中,导入模块的代码中,import后面的模块名称“matplotlib”“numpy”下面如果出现红色的波浪线,如图所示,就表示该模块还未导入。 模块名称“matplotlib”“numpy” 下面出现红色的波浪线 将鼠标指针移到出现红色波浪线(实际环境中)模块名称“matplotlib”位置,弹出提示信息框,如图所示。 鼠标指针指向模块名称“matplotlib”位置时弹出的提示信息框 按组合键【Alt+Enter】,出现一个快捷菜单,选择第一项【Install package matplotlib】,然后按【Enter】键或者单击执行该命令,如图所示。 执行【Install package matplotlib】命令 模块“matplotlib”成功安装完成,会出现图所示的提示信息。 模块“matplotlib”成功安装完成后出现的提示信息 以同样的操作方法安装模块“numpy”,模块“numpy”成功安装完成,会出现图所示的提示信息。 模块“numpy”成功安装完成后出现的提示信息 模块“matplotlib”和“numpy”成功安装完成后,import后面的模块名称“matplotlib”“numpy”下面的红色波浪线消失了,就表示该模块已成功导入。 4.编写Python程序代码 在新建文件5-1.py的代码编辑窗口已有模板注释内容下面输入程序代码,程序文件5-1.py的代码如电子活页5-1所示。 单击工具栏中的【保存】按钮,保存程序文件5-1.py。 5.运行Python程序 在PyCharm主窗口选择【Run】菜单,在弹出的下拉菜单中选择【Run】。在弹出的【Run】对话框中选择“5-1”选项,程序文件5-1.py开始运行。 程序文件5-1.py的运行结果如图所示。 程序文件5-1.py的运行结果 5.2 Python函数的定义与调用 使用函数能改善应用程序的模块化程度和提高代码的重复利用率,并能降低编程难度。函数是一种功能的抽象,一般函数会表达特定功能。函数是组织好的、可重复使用的、用来实现所需功能的、执行特定的任务的代码段,函数可以让代码执行得更快。函数是一段具有特定功能的、可重用的语句组。 5.2.1 定义函数 Python提供了许多内置的标准函数,例如print()、input()、range()等。我们也可以自己创建函数,这被称为自定义函数。 可以定义一个函数实现自己想要的功能,定义一个函数包括指定函数的名称、指定函数里包含的参数和代码块结构。 Python使用def关键字自定义函数,定义函数的一般基本语法格式如下。 def 函数名称([0个或多个参数组成的参数列表]): ''<注释内容>'' <函数体> return [表达式] 函数定义说明如下。 (1)函数定义部分以def关键字开头,后接函数名称、圆括号“ ()”和冒号“:”。函数名称在调用函数时使用,圆括号用于定义参数,任何传入参数和自变量必须放在圆括号内。如果有多个参数,各参数之间使用逗号“,”分隔;如果不指定参数,则表示该函数没有参数,调用函数时也不指定参数值。函数可以有参数也可以没有,但必须保留空的圆括号,否则会出现异常。默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配的。 (2)函数体是由多条语句组成的代码块,即该函数被调用时,要执行的功能代码。函数体的代码相对于def关键字必须保持合理的缩进。 (3)如果函数有返回值,使用return语句返回,return [表达式]用于退出函数,选择性地向调用方返回一个值。也可以让函数返回空值,不带表达式的return语句相当于返回None。函数的返回值可以是Python支持的任意数据类型,并且无论return语句出现在函数的哪一位置,只要该返回语句得以执行,就会直接结束函数的执行。 如果函数中没有return语句,或者省略了return语句的表达式,将返回None,即返回空值。 (4)函数体的前一行可以选择性地指定文本字符串注释,注释的内容包括函数功能、传递参数的作用等,注释字符串可以为用户提供友好提示和帮助信息,但并非函数定义的必须内容,也可以没有注释内容。如果有注释内容,这些注释内容相对于def关键字也必须保持合理的缩进。 (5)创建一个函数时,如果暂时不需要编写程序代码实现其功能,这时就可以使用pass语句作为占位符填充函数体,表示“以后会编写代码”。例如: def func(): pass #占位符 【实例5-1】演示计算矩形面积函数的定义 实例5-1的代码如下所示。 def area(width, height): '''计算矩形面积函数''' area=width * height return area 运行以上的代码,将不显示任何内容,也不会抛出异常,因为函数area()还没有调用。 5.2.2 调用函数 函数定义完成后,可以通过调用该函数执行函数代码,实现其功能。可以将函数作为一个值赋值给指定变量。 调用函数的基本语法格式如下。 函数名称([0个或多个参数组成的参数列表]) 要调用的函数名称必须是已经定义好的。如果已定义的函数有参数,则调用时也要指定各个参数值;如果需要传递多个参数值,则各参数之间使用逗号“,”分隔;如果该函数没有参数,则直接写圆括号“()”即可,但圆括号必须保留。 调用函数时,如果函数只返回一个值,则该返回值可以赋值给一个变量;如果返回多个值,则可以赋值给多个变量或一个元组。 实例5-1演示了自定义函数和函数调用,其完整代码如下所示。 def area(width, height): '''计算矩形面积函数''' area=width * height return area width = 4 height = 5 area= area(width, height) print("area =", area) 实例5-1的运行结果如下。 area = 20 【实例5-2】定义一个函数factorial(),计算n的阶乘 实例5-2的代码如下所示。 def factorial(m): s=1 for i in range(1,m+1): s*=i return s n=5 print("{0}!={1}".format(n,factorial(n))) 实例5-2中前5行代码为函数定义代码,最后一行中的factorial(n)为函数调用,调用时要给出实际参数n,实际参数替换定义中的参数m,函数调用后得到返回值s,返回给调用方。 实例5-2的运行结果如下。 5!=120 【任务5-2】应用日期时间函数实现倒计时功能 【任务描述】 (1)在项目Unit05中创建Python程序文件5-2.py。 (2)应用日期时间函数实现倒计时功能。 【任务实施】 1.创建Python程序文件5-2.py 在PyCharm项目Unit05中新建Python程序文件5-2.py,同时PyCharm主窗口显示程序文件5-2.py的代码编辑窗口,在该程序文件的代码编辑窗口自动添加了模板内容。 2.编写Python程序代码 在新建文件5-2.py的代码编辑窗口已有模板注释内容下面输入程序代码,程序文件5-2.py的代码如电子活页5-2所示。 单击工具栏中的【保存】按钮,保存程序文件5-2.py。 3.运行Python程序 在PyCharm主窗口选择【Run】菜单,在弹出的下拉菜单中选择【Run】。在弹出的【Run】对话框中选择“5-2”选项,程序文件5-2.py开始运行。程序文件5-2.py的运行结果如下。 Today 2020 年 4 月 8 日 距离: 北京冬奥会还有:666 天 【任务5-3】定义函数计算总金额、优惠金额和实付金额等 【任务描述】 (1)在项目Unit05中创建Python程序文件5-3.py。 (2)定义函数计算总金额、优惠金额和实付金额等。 【任务实施】 在PyCharm项目Unit05中创建Python程序文件5-3.py。在程序文件5-3.py中编写程序代码,实现所需功能,程序文件5-3.py的代码如电子活页5-3所示。 程序文件5-3.py的运行结果如下。 总金额: 367.26 运费: 0.00 返现金额:- 150.00 优惠金额:- 15.00 实付总额: 202.26 5.3 Python函数参数 在调用函数时,对于有参数的函数,调用函数和被调用函数之间就有数据传递关系。函数参数的作用是传递数据给函数使用,函数利用接收的数据进行具体的处理。 函数参数在定义时放在函数名称后面的圆括号中,如下所示。 5.3.1 Python函数的参数传递 1.形式参数和实际参数 (1)形式参数。定义函数时,函数名称后面圆括号中的参数称为“形式参数”,简称形参。 (2)实际参数。调用函数时,函数名称后面圆括号中的参数称为“实际参数”,也就是函数的调用者提供给函数的参数,简称实参。 形参与实参如下所示。 根据实参的类型不同,可以将实参的值或实参的引用传递给形参。当实参为不可变对象时,传递实参的值;当实参为可变对象时,传递实参的引用。值传递和引用传递的基本区别是:对于值传递,改变形参的值,实参的值不会改变;对于引用传递,改变形参的值,实参的值也一同改变。 2.可变对象与不可变对象的参数传递 Python中,列表、字典是可变对象,而数值、元组、字符串是不可变对象。 Python中一切都是对象,严格意义上不能说值传递和引用传递,应该说传不可变对象和传可变对象。 (1)可变对象的参数传递。 对于代码x=[1,2,3],[1,2,3]是列表类型。 变量先赋值x=[1,2,3,4],再赋值x[2]=5,则是将列表的第3个元素值进行更改,本身x没有变化,只是其内部的一部分值被修改了。 参数传递的如果是可变对象,就类似c++的引用传递,包括列表、字典等对象。例如函数fun(x),则是将x真正地传过去,在函数fun(x)内部修改x的值,修改后函数fun()外部的x也会受影响。 对于可变对象作函数参数,在函数里修改了参数的值,那么在调用这个函数时原始参数也被改变了。 【实例5-3】演示可变对象的参数传递 实例5-3的代码如下所示。 #可变对象参数实例 def mutable(mylist): #修改传入的列表 mylist.append([40,50]) print("函数内取值:", mylist) return #调用mutable()函数 mylist = [10, 20, 30] mutable(mylist) print("函数外取值:", mylist) 实例5-3中传入函数和在末尾添加新内容的对象用的是同一个引用。 实例5-3的运行结果如下。 函数内取值:[10, 20, 30, [40, 50]] 函数外取值:[10, 20, 30, [40, 50]] (2)不可变对象的参数传递。 在Python中,类型属于对象,变量是没有类型的。对于代码y=5,数值5是整数类型,而变量y没有类型,它仅仅是一个对象的引用,可以指向列表类型对象,也可以指向整数类型对象。 变量先赋值y=5,再赋值y=10,这里实际是新生成一个整数值对象10,再让y指向它,而5被丢弃,不是改变y的值,相当于新生成了y。 参数传递的如果是不可变对象,就类似c++的值传递,包括数值、元组和字符串等对象。例如fun(x),传递的只是x的值,没有影响x对象本身。在fun(x)内部修改x的值,只是修改另一个复制的对象,不会影响x本身。 【实例5-4】演示不可变对象的参数传递 实例5-4的代码如下所示。 #不可变对象参数实例 def immutable(y): y= 5 print("变量y值为:", y) #结果是5 return y x = 2 print("函数返回值为:",immutable(x)) print("变量x值为:",x ) #结果是2 实例5-4中有整数对象2,指向它的变量是x,在传递给immutable()函数时,按传递值的方式复制了变量x,x和y都指向了同一个整数对象。在y=5时,则新生成一个整数值对象5,并让y指向它。 实例5-4的运行结果如下。 变量y值为: 5 函数返回值为: 5 变量x值为: 2 5.3.2 Python函数参数类型 调用函数时可使用的函数参数类型有位置参数、关键字参数、默认值参数和不定长参数等。 1.位置参数 位置参数也称为必需参数。调用函数时,对于函数的位置参数必须以正确的顺序传入函数,参数数量也必须和定义函数时一样,即调用函数的位置和数量必须和定义时是一样的。调用函数时,如果指定的实参数量与形参数量不一致会出现TypeError异常,并提示缺少必要的位置参数。如果指定的实参位置与形参位置不一致,有时会出现TypeError异常,有时不会抛出异常,而是出现得到的结果与预期不符的问题,即产生bug。 【实例5-5】演示位置参数必须按指定顺序传递的情形 实例5-5的代码如下所示。 def printInfo(name, age,gender): #"输出对应传入的字符串" print("姓名:", name) print("年龄:", age) print("性别:", gender) return #调用printInfo()函数 printInfo("LiMing",21,"男") 实例5-5的函数printInfo()有3个参数,其顺序依次为name、age、gender,所以调用该函数时必须传递3个参数值,并且参数值的顺序也必须对应。这里传递的参数值依次为"LiMing"、21、"男",实例5-5的运行结果如下。 姓名: LiMing 年龄: 21 性别: 男 2.关键字参数 关键字参数是指使用形参的名称来确定传递的参数值,函数调用可以使用“key=value”的关键字参数形式,关键字参数用来确定传入的参数值。 使用关键字参数允许函数调用时参数的顺序与声明不一致,只要参数名称正确即可,因为Python解释器能够用参数名匹配参数值。这样可以避免需要牢记参数位置的麻烦,使得函数调用和参数传递更加灵活、方便。 【实例5-6】演示必需参数不需要按指定顺序传递的情形 实例5-6的代码如下所示。 def printInfo(name, age,gender): #"输出传入的字符串" print("姓名:", name,end=" ") print("年龄:", age,end=" ") print("性别:", gender) return #调用printInfo()函数 printInfo(name="LiMing",age=21,gender="男") printInfo(age=21,name="LiMing",gender="男") printInfo(gender="男",age=21,name="LiMing") 实例5-6的函数printInfo()也有3个参数,其顺序依次为name、age、gender。调用该函数时,如果使用“key=value”的关键字参数形式传递3个参数值,参数值的顺序可以为任意顺序,其运行结果都相同,与预期结果完全一致。实例5-6的运行结果如下。 姓名: LiMing 年龄: 21 性别: 男 姓名: LiMing 年龄: 21 性别: 男 姓名: LiMing 年龄: 21 性别: 男 3.默认值参数 定义函数时可以为某些参数定义默认值,构成可选参数。调用参数设置了默认值的函数时,如果没有传递参数值,则会直接使用定义函数时设置的默认值参数。 定义带有默认值参数的函数的基本语法格式如下。 def 函数名称(… , [ 参数名称=参数的默认值 ]): <函数体> return [表达式] 定义函数时,指定默认的形参必须位于所有参数的最后,否则将会发生语法错误。并且要求默认参数必须指向不可变对象,如果使用可变对象作为函数参数的默认值,多次调用时可能会出现结果不一致的情况。 【实例5-7】演示调用函数时没有传入参数值使用默认值的情形 实例5-7中如果没有传入nation参数值,则使用默认值"汉族",代码如下所示。 def printInfo(name, age, nation="汉族"): #"输出任何传入的字符串" print("姓名:", name,end=" ") print("年龄:", age,end=" ") print("民族:", nation) return #调用printInfo()函数 printInfo(name="LiMing",age=21,nation="壮族") printInfo(name="LiMing",age=20) 实例5-7的运行结果如下。 姓名: LiMing 年龄: 21 民族: 壮族 姓名: LiMing 年龄: 20 民族: 汉族 4.不定长参数 在实际开发程序时,可能需要一个函数能处理比当初定义时更多的参数,这些参数称为不定长参数或可变个数的参数列表,即调用函数时,传入函数的实际参数可以是0个、1个、2个到任意个。 (1)以元组形式给不定长参数传递多个参数值 以元组形式给不定长参数传递多个参数值时,不定长参数前面带1个星号“*”,这种形式定义函数的基本语法格式如下。 def functionName([formal_args,] *var_args_tuple ): <函数体> return [expression] 加了1个星号“*”的参数会存放到一个元组中,然后以元组的形式导入,该元组存放所有未命名的0个或多个参数值。 【实例5-8】演示以元组形式给不定长参数传递多个参数值 实例5-8中的函数printInfo()包含两种参数,参数arg1是一个必需参数,参数*args包含1个“*”,以元组形式存放所有未命名的参数值,该参数也可以命名为其他名称。其代码如下所示。 def printInfo(arg1, *args): # "输出任何传入的参数" print("输出:", end="") print(arg1,end="") print(args) #调用printInfo()函数 printInfo("weight",10, 20, 30) printInfo("cherry","apple", "pear", "peach","cherry") 实例5-8的运行结果如下。 输出:weight(10, 20, 30) 输出:cherry('apple', 'pear', 'peach', 'cherry') 调用包含不定长参数的函数时如果没有向不定长参数传递参数值,则该不定长参数就是一个空元组。 如果想要使用一个已经存在的列表作为参数的不定长参数,可以在列表的名称前加1个星号“*”,例如: fruits=["apple", "pear", "peach","cherry"] printInfo("cherry",*fruits) 其运行结果与printInfo("cherry","apple", "pear", "peach","cherry")的调用形式相同。 【实例5-9】演示给不定长参数传递参数值的多种情形 实例5-9中,第1次调用函数printInfo()时,传递了4个参数值;第2次调用函数printInfo()时,只传递了1个参数值,也就是不定长参数没有传递参数值。其代码如下所示。 def printInfo(arg1, *args): # "输出任何传入的参数" print("输出:", end="") print(arg1,end=" ") for item in args: print(item,end=" ") print("") return #调用printInfo()函数 printInfo("weight",10, 20, 30) printInfo("cherry") 实例5-9的运行结果如下。 输出:weight 10 20 30 输出:cherry (2)以字典形式给不定长参数传递多个参数值。 以字典形式给不定长参数传递多个参数值时,不定长参数前带2个星号“**”,这种形式定义函数的基本语法格式如下。 def functionName([formal_args,] **var_args_dict ): <函数体> return [expression] 加了2个星号“**”的参数会存放在一个字典中,然后以字典的形式导入,该字典存放所有未命名的0个或多个参数值。 【实例5-10】演示以字典形式给不定长参数传递多个参数值 实例5-10的函数printInfo()包含两种参数,参数arg1是一个必需参数,参数**args包含2个“**”,以字典形式存放所有未命名的参数值,该参数也可以命名为其他名称。调用该函数时,传递给参数dict的参数必须为关键字参数形式“key=value”,其代码如下所示。 def printInfo(arg1, **dict): # "输出任何传入的参数" print("输出:", end="") print(arg1,end=" ") print(dict) for key,value in dict.items(): print(key,":",value,end=" ") return #调用printInfo()函数 printInfo("student",name="LiMing",age=21,nation="壮族") 实例5-10的运行结果如下。 输出:student {'name': 'LiMing', 'age': 21, 'nation': '壮族'} name : LiMing age : 21 nation : 壮族 如果想要使用一个已经存在的字典作为参数的不定长参数,可以在字典的名称前加2个星号“**”,例如: fruits={"name":"LiMing","age":21,"nation":"壮族"} printInfo("student",**fruits) 其运行结果与printInfo("student",name="LiMing",age=21,nation="壮族")的调用形式相同。 5.组合参数 定义函数时包含多种形式的参数,如必需参数、不定长参数*args和**kwargs,该参数也可以命名为其他名称。*args是可变参数,args接收的是一个元组;**kwargs是关键字参数,kwargs接收的是一个字典。*args和**kwargs同时使用时,*args参数必须要位于**kwargs参数的前面。 【实例5-11】演示定义函数时包含多种形式的参数 实例5-11中所定义的函数包含了1个必需参数和两种形式的不定长参数*args和**kwargs,其代码如下所示。 def printInfo(num,*args,**kwargs): print("第"+str(num)+"组数据:") print("args=",args) print("kwargs=",kwargs) print("-----------------------------------------------------") if __name__ == '__main__': printInfo(1,80,85,94,91) printInfo(2,name="ZhangSan",age=19,gender="男") printInfo(3,82,91,86,92,name="LiSi",age=20,gender="女") printInfo(4,"WangWu",20,None,name="ZhaoLiu",age=21,gender="男") 实例5-11的运行结果如下。 第1组数据: args= (80, 85, 94, 91) kwargs= {} ----------------------------------------------------- 第2组数据: args= () kwargs= {'name': 'ZhangSan', 'age': 19, 'gender': '男'} ----------------------------------------------------- 第3组数据: args= (82, 91, 86, 92) kwargs= {'name': 'LiSi', 'age': 20, 'gender': '女'} ----------------------------------------------------- 第4组数据: args= ('WangWu', 20, None) kwargs= {'name': 'ZhaoLiu', 'age': 21, 'gender': '男'} ----------------------------------------------------- 6.强制位置参数 定义函数时,参数中星号“*”也可以单独出现,并且单独出现星号“*”后的参数必须用关键字参数形式“key=value”传入。 例如: >>>def fun(a,b,*,c): return a+b+c >>>fun(1,2,c=3) #正常 运行结果如下。 6 对于以下形式的函数调用,会出现异常。 >>>f(1,2,3) Traceback (most recent call last): File "", line 1, in TypeError: f() takes 2 positional arguments but 3 were given Python 3.8新增了一个函数形参语法,使用“/”指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。 在以下的实例中,形参a和b必须使用指定位置参数,c或d可以是位置形参或关键字形参,而e或f要求为关键字形参。 >>>def fun(a, b, /, c, d, *, e, f): print(a, b, c, d, e, f) 以下的函数调用形式是正确的。 >>>fun(10, 20, 30, d=40, e=50, f=60) 运行结果如下。 10 20 30 40 50 60 以下的函数调用形式会出现异常。 >>>fun(10, b=20, c=30, d=40, e=50, f=60) #b不能使用关键字参数的形式 出现的异常信息如下。 Traceback (most recent call last): File "", line 1, in TypeError: fun() got some positional-only arguments passed as keyword arguments: 'b' >>>fun(10, 20, 30, 40, 50, f=60) #e必须使用关键字参数的形式 出现的异常信息如下。 Traceback (most recent call last): File "", line 1, in TypeError: fun() takes 4 positional arguments but 5 positional arguments (and 1 keyword-only argument) were given 【任务5-4】自定义函数应用多种方法对齐输出图书数据 【任务描述】 (1)在项目Unit05中创建Python程序文件5-4.py。 (2)综合应用多种方法对齐输出图书数据。 【任务实施】 在PyCharm项目Unit05中创建Python程序文件5-4.py。在程序文件5-4.py中编写程序代码,实现所需功能,程序文件5-4.py的代码如电子活页5-4所示。 程序文件5-4.py的运行结果如图所示。 程序文件5-4.py的运行结果 5.4 函数变量的作用域 变量的作用域是指程序代码能够访问该变量的区域范围,如果超出该区域范围,访问该变量时就会出现异常。在Python中,一般会根据变量的“有效范围”,将变量分为“局部变量”和“全局变量”两种类型。 1.局部变量 局部变量是指在函数内部定义并使用的变量,它只在函数内部有效,即定义在函数内部的变量拥有一个局部作用域,函数内部的名称只在函数运行时才会创建,在函数运行之前或运行完毕,所有的局部变量的名称都不存在了。如果在函数外部使用函数内部定义的变量,就会出现NameError异常。 2.全局变量 全局变量是指能够作用于函数内部和外部的变量,全局变量主要有以下两种情况。 (1)在函数外定义的变量拥有全局作用域。如果一个变量在函数外部定义,那么该变量不仅可以在函数外访问,在函数内部也可以访问。 【实例5-12】演示Python全局变量与局部变量的使用 实例5-12的代码如下所示。 age = 20 #全局变量 def printAge1(): age = 50 #局部变量 print("函数printAge1()中输出局部变量:age=", age) def printAge2(): print("函数printAge2()中输出全局变量:age=", age) printAge1() printAge2() print("函数外部输出全局变量:age=", age ) 实例5-12的运行结果如下。 函数printAge1()中输出局部变量:age= 50 函数printAge2()中输出全局变量:age= 20 函数外部输出全局变量:age= 20 (2)对于在函数内部定义的变量,如果使用global关键字声明后,该变量也是全局变量,在函数外部可以访问到该变量,并且在函数内部还可以对其进行修改,但是在其他函数内部不能访问该变量。 【实例5-13】演示全局变量的两种使用形式 实例5-13的代码如下所示。 global_grade = "三等奖" #全局变量 print("函数外部输出全局变量:国内技能竞赛获奖等级:", global_grade ) def printRank1(): local_grade = "一等奖" #局部变量 print("函数printRank1()内输出局部变量:小组内技能竞赛获奖等级:", local_grade) print("函数printRank1()内输出全局变量:国内技能竞赛获奖等级:", global_grade) def printRank2(): global grade #使用关键字global定义的全局变量grade grade = "二等奖" print("函数printRank2()内输出全局变量1:省内技能竞赛获奖等级:", grade) print("函数printRank2()内输出全局变量2:国内技能竞赛获奖等级:", global_grade) printRank1() printRank2() print("函数外部输出全局变量1:省内技能竞赛获奖等级:", grade) print("函数外部输出全局变量2:国内技能竞赛获奖等级:", global_grade) 实例5-13的运行结果如下。 函数外部输出全局变量:国内技能竞赛获奖等级: 三等奖 函数printRank1()内输出局部变量:小组内技能竞赛获奖等级: 一等奖 函数printRank1()内输出全局变量:国内技能竞赛获奖等级: 三等奖 函数printRank2()内输出全局变量1:省内技能竞赛获奖等级: 二等奖 函数printRank2()内输出全局变量2:国内技能竞赛获奖等级: 三等奖 函数外部输出全局变量1:省内技能竞赛获奖等级: 二等奖 函数外部输出全局变量2:国内技能竞赛获奖等级: 三等奖 实例5-13中全局变量global_grade是在函数外定义的,在函数外和两个函数内部都允许访问;全局变量grade是在函数printRank2()内部定义并赋值的,在函数printRank2()内部和函数外都允许访问,但在另一个函数printRank1()内部不能访问;局部变量local_grade是在函数printRank1()内部定义并赋值的,只能在函数printRank1()内部访问,在函数外和另一函数printRank2()内部都无法访问。 5.5 Python的模块创建与导入 Python提供了强大的模块支持,不仅Python自身提供了大量的标准模块,而且还有很多第三方提供的模块,也允许自定义模块。这些强大的模块支持提高了代码的可重用性,即编写好一个模块后,只要是实现该功能的程序,都可以导入这个模块来实现所需的功能,这样就极大地提高了程序开发效率。 Python的模块是一个包含函数定义和变量定义的Python文件,其扩展名也是“.py”。一般把能够实现一定功能的代码放置在一个Python文件中作为一个模块,模块可以被别的程序引入并使用,方便其他程序使用该模块中的函数等功能。另外,使用模块可以避免函数名称和变量名称产生冲突。 模块除了包含函数定义,还可以包含可执行的代码,这些代码一般用来初始化模块。只有在模块第1次被导入时才会被执行。 每个模块有各自独立的符号表,在模块内部被所有的函数当作全局符号表使用。所以在模块内部可以放心使用这些全局变量,而不用担心跟其他模块中的全局变量混淆。 5.5.1 创建模块 创建模块可以将相关的变量定义和函数定义编写在一个独立的Python文件中,并且将该文件命名为“模块名称.py”的形式,也就是说,创建模块实际就是创建一个模块文件,并且模块文件的扩展名必须是“.py”。创建模块时,设置的模块名称尽量不要与Python自带的标准模块名称重名。模块创建完成后,就可以在其他程序中导入并使用该模块了。 在“D:\PycharmProject\Unit05”位置创建一个自定义模块fibonacci.py,其代码如下所示。 #斐波那契(fibonacci)数列模块 def fib1(n): #定义到n的斐波那契数列 a, b = 0, 1 while b < n: print(b, end=' ') a, b = b, a+b print() def fib2(n): #返回到n的斐波那契数列 result = [] a, b = 0, 1 while b < n: result.append(b) a, b = b, a+b return result 自定义模块定义完成后,可以通过modname.itemname这样的表示法来访问模块内的函数。 例如: >>>fibonacci.fib1 5.5.2 导入模块 Python的模块或程序文件中可以导入其他模块的,可以使用import或者from…import语句来导入相应的模块。通常在一个模块或程序文件的最前面使用import语句来导入一个模块,当然这只是一个惯例,而不是强制要求的,被导入的模块名称将被导入当前操作模块的符号表中。 1.使用import语句导入模块 想要使用Python的模块文件中的变量或函数,需要在另一个文件里执行import语句加载模块中的代码,其基本语法格式如下。 import module1[, module2[,… moduleN] [as alias] 其中,module1, module2, …, moduleN表示要导入模块的名称,as alias为给模块命名的别名,通过该别名也可以使用该模块。 import语句允许一次导入多个模块,在导入多个模块时,模块名称之间使用逗号“,”分隔,但这种做法不推荐使用,因为降低了代码的可读性。 当解释器遇到import语句,如果模块位于当前的搜索路径中就会被导入,搜索路径是一个解释器会先进行搜索的所有文件夹的列表。 一个模块只会被导入一次,不管执行了多少次import语句,这样可以防止导入的模块被一遍又一遍地执行。 打开Windows的【命令提示符】窗口,在该窗口提示符“>”后面输入命令“D:”,按【Enter】键,将当前盘更换为D盘。然后输入命令“cd D:\PycharmProject\Unit05”,按【Enter】键,将当前文件夹更换为Unit05。 接着在当前的提示符后面输入“python”,按【Enter】键,出现提示信息,同时进入交互式Python解释器中,提示符变为“>>>”,等待用户输入Python命令。 在提示符“>>>”后面输入以下命令导入前面创建的自定义模块fibonacci。 >>>import fibonacci 这种导入的方法并没有把直接定义在fibonacci.py文件中的函数名称导入当前的符号表中,只是把模块fibonacci的名称准备在那里了。 调用模块中的变量、函数时,需要在变量名称、函数名称前添加“模块名称.”作为前缀,例如fibonacci.fib1()、fibonacci.fib2()。 例如: >>>fibonacci.fib1(100) 运行结果如下。 1 1 2 3 5 8 13 21 34 55 89 >>>fibonacci.fib2(100) 运行结果如下。 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] >>>fibonacci.__name__ 运行结果如下。 'fibonacci' 调用模块fibonacci中自定义函数fib1()、fib2()的执行结果如图所示。 调用模块fibonacci中自定义函数fib1()、fib2()的执行结果 如果模块名称比较长,不容易记住,可以在导入模块时,使用as关键字为该模块名称设置一个别名,然后就可以通过这个别名来调用模块中的变量、函数等对象。 例如,使用turtle模块绘制时使用以下代码。 import turtle as t t.penup() #抬笔 t.goto(x, y) #画笔起始位置 t.pencolor(rectcolor) #画笔颜色 t.pendown() #落笔 t.fillcolor(rectcolor) #设置填充颜色 如果经常使用一个函数,可以将该函数名称赋给一个本地的变量名称,然后通过本地的变量名称调用模块中的自定义函数,例如: >>>fib= fibonacci.fib1 >>>fib(100) 运行结果如下。 1 1 2 3 5 8 13 21 34 55 89 2.使用from…import语句导入模块 使用import语句导入模块时,每执行一条import语句都会创建一个新的命名空间(namespace),并且在该命名空间中执行与.py文件相关的所有语句。在执行时,需要在具体的变量、函数名称前加上“模块名称.”前缀。如果不想在每次导入模块时都创建一个新的命名空间,而是想将具体的定义导入当前的命名空间,这时可以使用from…import语句。使用from…import语句导入模块后,不需要再添加“模块名称.”前缀,直接通过具体的变量、函数名称访问即可。 Python的from语句的功能是从模块中导入一个指定的函数或变量的名称到当前模块中,基本语法格式如下。 from modename import name1[, name2[, … nameN]] 其中,modename表示导入的模块名称,区分字母大小写,需要和定义模块时设置的模块名称的大小写保持完全一致。name1、name2、nameN表示要导入的变量、函数名称。可以同时导入多个变量和函数,各个对象之间使用逗号“,”分隔。 例如,要导入模块fibonacci的fib1()和fib2()函数,使用如下语句。 >>>from fibonacci import fib1, fib2 >>>fib1(100) 运行结果如下。 1 1 2 3 5 8 13 21 34 55 89 这里的声明不会把整个fibonacci模块导入当前的命名空间中,它只会将fibonacci模块中的两个函数fib1()和fib2()导入。 3.使用from…import * 语句导入模块中的所有对象 还有一种方法,可以一次性把一个模块中的所有函数、变量名称全部都导入当前模块的符号表,基本语法格式如下。 from modname import * 这将导入所有的函数、变量名称,但是那些由单一下画线“_”开头的变量名称(局部变量)不在此列。这个声明提供了一个简单的方法来导入一个模块中的所有对象,但通常并不主张使用这种方法导入模块,因为这种方法经常会导致代码的可读性降低,这样导入引入的其他模块的名称,有可能覆盖了本模块中已有的定义的名称。 4.Python模块的搜索路径 当我们使用import语句导入模块的时候,Python解释器是怎样找到对应的文件的呢? 这就涉及Python的搜索路径。搜索路径是由一系列文件夹名称组成的,Python解释器依次从这些文件夹中去寻找所引入的模块。这看起来很像环境变量,事实上也可以通过定义环境变量的方式来确定搜索路径。搜索路径是在Python编译或安装的时候确定的,安装新的库也会自动进行修改。 默认情况下,会按照以下顺序进行查找。 (1)在当前文件夹(当前正在执行的Python文件所在的文件夹)下查找。 (2)在环境变量中指定的每个文件夹中查找。 (3)在Python的默认安装文件夹中查找。 搜索路径被存储在sys模块中的path变量中,可以通过以下代码输出搜索路径所在的文件夹。 >>>import sys >>>print(sys.path) 运行结果如下。 ['', 'D:\\Python\\Python3.8.2\\python38.zip', 'D:\\Python\\Python3.8.2\\DLLs', 'D:\\Python\\Python3.8.2\\lib', 'D:\\Python\\Python3.8.2', 'C:\\Users\\Administrator\\AppData\\Roaming\\Python\\Python38\\site-packages', 'D:\\Python\\Python3.8.2\\lib\\site-packages'] 如果导入的模块不在以上运行结果所示的文件夹中,那么在导入模块时,将会出现异常。 5.5.3 导入与使用Python的标准模块 Python本身带有一些标准的模块库,这里介绍两个常用的标准模块。 1.sys模块 sys模块是与Python解释器及其环境操作相关的标准模块。导入与使用sys模块的代码如下。 >>>import sys >>>for item in sys.argv: print (item) >>>print('python路径:',sys.path) 导入sys模块的argv、path成员的代码如下。 >>>from sys import argv,path #导入特定的成员 >>>print('path:',path) #因为已经导入path成员,所以此处引用时不需要加“sys.” sys模块还有stdin、stdout和stderr属性,即使在stdout被重定向时,stderr也可以用于显示警告和错误信息。 例如: >>>sys.stderr.write('Warning, log file not found starting a new one\n') 运行结果如下。 Warning, log file not found starting a new one 47 大多数脚本的定向终止都使用"sys.exit()"语句。 2.os模块 os模块提供了不少与操作系统相关联的函数。导入与使用os模块的代码如下。 >>>import os >>>os.getcwd() #返回当前的工作目录 运行结果如下。 'D:\\PycharmProject\\Unit05' >>>os.chdir('D:\PycharmProject') #修改当前的工作目录 >>>os.system('mkdir Test05') #执行系统命令mkdir 运行结果如下。 0 建议使用import os格式导入os模块而非使用from os import *格式,这样可以保证随操作系统不同而有所变化的os.open()语句不会覆盖内置函数open()。 在使用os模块这样的大型模块时,内置的dir()和help()函数非常有用,例如: >>>import os >>>help(os) 返回函数或模块功能的详细说明。 >>>dir(os) 返回os模块中所有对象的列表。 5.5.4 使用内置函数dir() 内置函数dir()可以找到模块内定义的所有名称,并以字符串列表的形式返回。 dir()函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用;如果参数不包含方法__dir__(),该方法将最大限度地收集参数信息。 例如: >>>import fibonacci >>>dir(fibonacci) 运行结果如下。 ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'fib1', 'fib2'] 其中,fib1和fib2就是我们导入的自定义函数名称。 >>>a = [1, 2, 3, 4, 5] >>>import fibonacci >>>fib = fibonacci.fib1 >>>dir() #得到一个当前模块中定义的属性列表 如果没有给定参数,那么dir()函数会罗列出当前定义的所有名称。运行结果如下。 ['__annotations__', '__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'fib', 'fibonacci'] 5.5.5 __name__属性与以主程序的形式执行 一个模块被第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,可以用__name__属性来使该程序块仅在该模块自身运行时执行。无论是隐式的还是显式的相对导入都是从当前模块开始的。主模块的名字永远是“__main__”,一个Python应用程序的主模块应当总是使用绝对路径引用。 代码如下。 >>>if __name__ == '__main__': print('程序自身在运行') else: print('我来自另一模块') 运行结果如下。 程序自身在运行 【任务5-5】编写程序自定义模块与函数格式输出商品信息 【任务描述】 (1)在项目Unit05中创建Python程序文件5-5.py。 (2)自定义模块commonModult.py,在该模块中自定义函数printField()、printFormatData()、printBlankFill(),分别用于输出表格标题行、格式化输出商品信息、输出填充空格。 (3)编写程序自定义模块与函数格式输出商品信息。 【任务实施】 1.创建模块文件commonModult.py 在项目文件夹PycharmProject中创建模块文件commonModult.py,在该模块中分别定义4个函数,名称分别为:getSize()、printField()、printFormatData()、printBlankFill()。模块commonModult的代码如电子活页5-5所示。 2.创建Python程序文件5-5.py 在PyCharm项目Unit05中创建Python程序文件5-5.py。在程序文件5-5.py中编写程序代码,实现所需功能。程序文件5-5.py的代码如下所示。 from commonModult import printFormatData , printBlankFill , printField def printData(bookData): for row in bookData: printFormatData(row[0], "^", "6d") printFormatData(row[1], "<", "24s") printBlankFill(row[1], "") printFormatData(row[2], "^", "8.2f") printFormatData(row[3], "^", "12s") print("") fieldName=("商品ID","图书名称","价格","出版日期") bookData = [(1,"HTML5+CSS3移动Web开发实战", 58.00, "2019-5-1"), (2,"给Python点颜色 青少年学编程", 59.80, "2019-9-1"), (3,"PPT设计从入门到精通",79.00,"2019-1-1"), ] printField(fieldName) printData(bookData) 3.运行程序文件5-5.py 程序文件5-5.py的运行结果如图所示。 程序文件5-5.py的运行结果 5.6 Python中创建与使用包 使用模块可以避免函数名称、变量名称重名引发的命名冲突,如果模块名称也重名应该怎么办呢?Python的包(package)可以解决模块名称冲突的问题。包是一个分层的目录结构,它将一组功能相近的模块组织在一个文件夹中,这样既可以起到规范代码的作用,又能避免模块重名引起的命名冲突。 包简单理解就是“文件夹”,只不过在该文件夹下必须存在一个名称为“__init__.py”的文件。实际开发软件项目时,会创建多个包用于存放不同类型的文件。 包是一种管理Python模块命名空间的形式,采用“包名称.模块名称”的形式。例如一个模块的名称是A.B,那么它表示一个包A中的子模块B。就好像使用模块的时候,不用担心不同模块之间的全局变量相互影响一样,采用“包名称.模块名称”这种形式也不用担心出现不同库之间的模块重名的问题。 5.6.1 创建包 在PyCharm集成开发环境中创建包的步骤如下。 (1)在PyCharm主窗口右键单击已建好的PyCharm项目,例如“PycharmProject”,在弹出的快捷菜单中选择【New】-【Python Package】,如图所示。 在快捷菜单中选择【New】-【Python Package】 (2)在打开的【New Package】对话框中输入包名称“package01”,如图所示。然后按【Enter】键即可完成Python包的创建任务。 【New Package】对话框 以同样的方法再创建另一个包package02,PyCharm项目“PycharmProject”中创建2个包的结构如图所示。 PyCharm项目“PycharmProject”中创建2个包的结构 从图中可以看出新创建的2个包中都自动添加了__init__.py文件。 (3)在包中创建模块。包package01创建完成后,就可以在该包中创建所需的模块了,这里创建模块myModule01.py。在PyCharm主窗口右键单击已建好的PyCharm包“package01”,在弹出的快捷菜单中选择【New】-【Python File】,在打开的【New Python file】对话框中输入Python模块名称“myModule01.py”,然后双击“Python file”选项,完成Python模块的新建任务。 同样,包package02创建完成后,就可以在该包中创建所需的模块了,这里创建模块myModule02.py,以同样的方法在包package02中新建模块myModule02.py。 (4)编写包中模块myModule01.py的程序代码。模块myModule01.py的程序代码如下。 globalAttribute = "global:全局变量" width = 2560 height= 1600 def printStar(): print("☆☆☆☆☆☆☆☆☆☆☆☆") def resolution(): print("物理分辨率:",width,"×", height,"像素") if __name__=="__main__": strModule="myModule01" print("这是运行了模块"+strModule+"中的输出语句") 在PyCharm主窗口单击工具栏中的【保存】按钮,保存模块myModule01.py。 (5)编写包中模块myModule02.py的程序代码。模块myModule02.py的程序代码如下。 strInfo="物理分辨率:" def width(w): return w def height(h): return h def resolution(info,w,h): print(info,width(w),"×", height(h),"像素") 在PyCharm主窗口单击工具栏中的【保存】按钮,保存模块myModule02.py。 5.6.2 使用包 包中所需的模块创建完成后,就可以在Python程序代码中使用import语句从包中加载模块。从包中加载模块通常有以下3种方式。 1.通过“import+完整包名称+模块名称”形式加载指定模块 对于包package01中的模块myModule01,导入myModule01模块的代码如下。 import package01.myModule01 通过这种方式导入模块myModule01后,使用模块myModule01中的变量和函数时,需要使用完整的名称,要在变量名称和函数名称前加“package01.myModule01.”前缀。 【实例5-14】演示通过“import+完整包名称+模块名称”形式加载指定模块在变量名称和函数名称前加“package01.myModule01.”前缀的情形 实例5-14的代码如下所示。 import package01.myModule01 print("输出模块myModule01中的全局变量:", package01.myModule01.globalAttribute) package01.myModule01.printStar() 实例5-14的运行结果如下。 输出模块myModule01中的全局变量: global:全局变量 ☆☆☆☆☆☆☆☆☆☆☆☆ 2.通过“from+完整包名称+import+模块名称”形式加载指定模块 对于包package01中的模块myModule01,导入myModule01模块的代码如下。 from package01 import myModule01 通过这种方式导入模块myModule01,在使用myModule01中的变量和函数时,不需要带包名前缀“package01.”,但需要带模块名前缀“myModule01.”,示例代码如下。 myModule01.resolution() 3.通过“from+完整包名称+模块名称+import+变量名称或函数名称”形式加载指定模块 对于包package02中的模块myModule02,导入myModule02模块定义的变量和函数的代码如下。 from package02.myModule02 import strInfo,resolution 通过这种方式导入模块的变量、函数后,直接使用变量、函数名称即可。 通过“from+完整包名称+模块名称+import+变量名称或函数名称”形式加载指定模块时,可以使用星号“*”代替多个变量或函数名称,表示加载该模块中的全部定义,例如: from package02.myModule02 import * 【实例5-15】演示通过“from+完整包名称+模块名称+import+变量名称或函数名称”形式加载指定模块和通过“from+完整包名称+import+模块名称”形式加载指定模块两种情形 实例5-15的代码如下所示。 from package01 import myModule01 from package02.myModule02 import strInfo,resolution if __name__=="__main__": print("调用包1的模块1中的函数"); myModule01.resolution() print("调用包2的模块2中的函数"); print(resolution(strInfo,3000,2000)) 实例5-15的运行结果如下。 调用包1的模块1中的函数 物理分辨率: 2560 × 1600 像素 调用包2的模块2中的函数 物理分辨率: 3000 × 2000 像素总结评价 本单元主要学习Python数学函数的应用、Python函数的定义与调用、Python函数参数、函数变量的作用域、Python的模块创建与导入、Python中创建与使用包。 展开更多...... 收起↑ 资源预览