Python编程及项目开发课件 第3章 Python函数及模块_第1页
Python编程及项目开发课件 第3章 Python函数及模块_第2页
Python编程及项目开发课件 第3章 Python函数及模块_第3页
Python编程及项目开发课件 第3章 Python函数及模块_第4页
Python编程及项目开发课件 第3章 Python函数及模块_第5页
已阅读5页,还剩45页未读 继续免费阅读

下载本文档

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

文档简介

PROGRAMMINGFUNDAMENTALS3.Python函数及模块从基础到实践的函数编程之旅代码复用模块化编程高效开发CONTENTS目录01函数基础概念理解函数的定义、调用与核心价值,掌握函数的基本语法结构02函数参数详解掌握默认参数、可变参数、关键字参数等多种参数类型03高级函数特性探索函数嵌套、lambda表达式与递归调用04变量作用域理解局部变量与全局变量的作用范围与使用规则05模块与包掌握模块化编程的核心技术与包的组织管理06项目开发实践通过实际项目巩固所学知识,掌握算法与综合应用01函数基础概念理解函数的定义、调用与核心价值掌握函数的基本语法结构与使用规范FunctionFundamentals01/CASEINTRODUCTION案例引入:多边形面积计算问题背景已知多边形各边长度,计算该多边形的面积。计算多边形的面积可分解为计算若干个三角形的面积。海伦公式:若已知三角形三条边x、y、z,面积Area=√[s(s-x)(s-y)(s-z)],其中s=(x+y+z)/2代码冗余问题观察右侧代码,发现有3组功能相同、代码相似的语句块(唯一不同的是三角形的边长不同)。如果是6边形、7边形……则多边形分解成的三角形会更多,求面积时相似的语句也会出现多组。原始实现代码#输入各边长度a=float(input('输入三角形边长a:'))b=float(input('输入三角形边长b:'))c=float(input('输入三角形边长c:'))d=float(input('输入三角形边长d:'))e=float(input('输入三角形边长e:'))f=float(input('输入三角形边长f:'))g=float(input('输入三角形边长g:'))#计算第一个三角形面积S1c1=(a+b+c)/2s1=(c1*(c1-a)*(c1-b)*(c1-c))**0.5#计算第二个三角形面积S2c2=(c+d+e)/2s2=(c2*(c2-c)*(c2-d)*(c2-e))**0.5#计算第三个三角形面积S3c3=(e+f+g)/2s3=(c3*(c3-e)*(c3-f)*(c3-g))**0.5s=s1+s2+s3print('多边形面积为%0.2f'%s)解决方案:我们能不能对这个功能进行自定义,然后在程序中多次调用这个功能呢?答案是肯定的,这就是函数!01/COREVALUE函数的核心价值模块化分解将复杂系统拆解为独立的、可复用的功能单元。模块化后,不同开发者可并行开发不同模块,提升团队协作效率。代码复用避免重复代码,减少代码冗余,降低维护成本。一次编写,多次调用,提高开发效率。抽象与封装隐藏实现细节,暴露清晰接口,降低耦合度,提升协作效率。使用者无需了解内部逻辑。可测试性函数作为最小测试单元,支持隔离测试,提高代码可靠性。便于单元测试和调试。可维护性隔离变化点,便于功能迭代,适应需求演进。修改一处,全局生效,降低维护难度。协作开发函数作为原子修改单位,便于代码审查和团队协作开发。多人协作更加高效有序。函数是对程序逻辑进行结构化或过程化的一种编程方法,就是将完成一定功能的代码段组合在一起01/DEFINITIONSYNTAX函数的定义语法基本语法结构deffunctionName(par1,par2,...):indentedblockofstatementsreturnexpression1函数代码块以def关键字开头,后接函数名和圆括号"()"2圆括号里用于定义参数(形参),多个参数用逗号","隔开3圆括号后边必须要加冒号":"4在缩进块中编写函数体5函数的返回值用return语句重要说明•一个函数体中可以有多条return语句,执行第一条return后函数立即终止•如果没有return语句,函数执行完毕后返回结果为None•Python中函数的声明和定义不加区别定义规则详解函数命名函数名应遵循标识符规则,使用小写字母和下划线,见名知意。如:calculate_area、get_user_info参数定义参数可以有多个,也可以没有。没有参数时圆括号内为空,但圆括号不能省略。缩进要求函数体必须使用相同的缩进(通常4个空格),Python通过缩进来识别代码块。返回值return可以返回单个值、多个值(以元组形式),或者不写return返回None。01/FUNCTIONEXAMPLE函数定义示例:三角形面积函数完整代码实现defarea(a,b,c):s=0#计算半周长c1=(a+b+c)/2#计算面积(海伦公式)s=(c1*(c1-a)*(c1-b)*(c1-c))**0.5returns函数解析def关键字定义函数的关键字area函数名见名知意,表示计算面积(a,b,c)参数三个形参,代表三条边长return返回值返回计算得到的面积设计思路功能封装:将计算三角形面积的逻辑封装成一个独立的功能单元参数设计:需要3个参数,分别代表三角形的三条边长a、b、c算法实现:使用海伦公式计算面积,先求半周长,再代入公式返回值:将计算结果通过return返回给调用者优势:封装后的函数可以在程序中多次调用,只需传入不同的边长参数,即可计算不同三角形的面积,避免代码重复!01/FUNCTIONCALL函数的调用方法调用内置函数Python内置了很多实用的函数,我们可以直接调用。要调用一个函数,需要知道函数的名称和参数。#调用max函数求最大值print(max([4,8]))#输出:8print(max([1,9,3]))#输出:9print(max([5]))#输出:5常见错误#错误1:参数数量不对max([])#ValueError:max()argisanemptysequence#错误2:参数类型不正确max([1,a])#NameError:name'a'isnotdefined调用函数时需正确输入参数个数和参数类型。调用自定义函数Python除了可以调用内置的函数外,也可以调用自定义的函数。#定义函数defarea(a,b,c):c1=(a+b+c)/2s=(c1*(c1-a)*(c1-b)*(c1-c))**0.5returns#调用函数a,b,c=3,4,5result=area(a,b,c)print(f"三角形面积:{result}")#多次调用s1=area(3,4,5)s2=area(5,12,13)s3=area(6,8,10)关键点:调用时传入的a、b、c称为实际参数(实参),函数定义时的参数称为形式参数(形参)。01/COMPLETECASE完整案例:多边形面积计算(函数版)重构后的代码#定义计算三角形面积的函数defarea(a,b,c):s=0c1=(a+b+c)/2s=(c1*(c1-a)*(c1-b)*(c1-c))**0.5returns#输入各边长度a=float(input('输入三角形边长a:'))b=float(input('输入三角形边长b:'))c=float(input('输入三角形边长c:'))d=float(input('输入三角形边长d:'))e=float(input('输入三角形边长e:'))f=float(input('输入三角形边长f:'))g=float(input('输入三角形边长g:'))#调用函数计算三个三角形面积s1=area(a,b,c)s2=area(c,d,e)s3=area(e,f,g)#计算总面积s=s1+s2+s3print('多边形面积为%0.2f'%s)改进对比原始代码重复代码3组,共21行计算逻辑函数版封装为函数,调用3次,仅3行核心优势代码复用:一次定义,多次调用易于维护:修改一处,全局生效逻辑清晰:封装细节,专注业务可扩展性:支持任意多边形函数让代码从重复走向优雅!01/EMPTYFUNCTION空函数与pass语句空函数定义defnothing():passpass语句的作用是占位符。对于还不确定怎么写的函数,可以先写一个pass,保证代码能运行。应用场景框架设计在设计阶段先定义函数接口,后续再实现具体逻辑待办事项标记需要后续完成的功能点,便于团队协作测试占位在单元测试中作为桩函数使用实际示例#定义一个待实现的函数框架defuser_login(username,password):#TODO:实现用户登录验证逻辑passdefuser_register(username,password,email):#TODO:实现用户注册逻辑passdefsend_email(to,subject,content):#TODO:实现发送邮件功能pass#主程序可以先调用这些函数user_login("admin","123456")user_register("newuser","password","user@")提示:pass语句不做任何事情,只是用来保持程序结构的完整性。在开发过程中合理使用pass可以提高开发效率。02函数参数详解掌握Python函数的各种参数类型与使用技巧理解默认参数、可变参数、关键字参数的组合应用FunctionParameters02/PARAMETEROVERVIEW参数概述与分类Python参数的灵活性定义Python函数的时候,就已经确定了函数的名字和位置。当我们调用函数的时候,只需要知道如何正确地传递参数以及函数的返回值,而函数内部的代码块具体是怎么实现功能的,调用函数者不必了解。Python的函数定义很简单却很灵活,尤其是参数。除了函数的必选参数外,还有默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。参数分类必选参数调用时必须传入的参数默认参数定义时指定默认值的参数可变参数接收任意数量的参数关键字参数接收带参数名的参数参数组合关系1必选参数最基础的参数类型,调用时必须提供2默认参数简化调用,提供默认值3可变参数处理不确定数量的参数4关键字参数接收额外的命名参数02/DEFAULTPARAMETERS默认参数详解问题引入我们可以定义power(x,n)函数来计算xⁿ。但如果计算平方比较普遍,每次调用都要写n=2会很麻烦。#原始定义defpower(x,n):#...计算x的n次方#调用power(4,2)#计算4²power(5,2)#计算5²如何简化这种常见情况的调用?解决方案#使用默认参数defpower(x,n=2):s=1whilen>0:n=n-1s=s*xreturnspower(6)→自动将n赋为2,相当于power(6,2),结果36power(2,3)→n=3,计算2³,结果8默认参数的优势简化函数调用只需定义一个函数,即可实现对该函数的多次调用,降低调用函数的难度。提高代码可读性常见情况使用默认值,特殊情况显式指定,代码意图更加清晰。向后兼容为函数添加新参数时,使用默认值可以保持原有调用方式不变。核心思想:变化大的参数位置靠前,变化小的参数位置靠后,变化小的参数即可作为默认参数。02/IMPORTANTNOTES默认参数的注意事项1赋值时机一个函数的默认参数,仅仅在该函数定义的时候,被赋值一次。#默认参数在定义时赋值deffunc(a,b=5):#b=5在定义时确定

returna+b2参数位置默认参数的位置必须在必选参数的后面,否则Python的解释器会报语法错误。#错误示例deffunc(a=5,b):#❌语法错误#正确示例deffunc(b,a=5):#✓正确SyntaxError:non-defaultargumentfollowsdefaultargument3变化频率在设置默认参数时,变化大的参数位置靠前,变化小的参数位置靠后,变化小的参数即可作为默认参数。最佳实践:将最常用的值设为默认参数,减少调用时的参数传递。4不可变对象默认参数一定要用不可变对象。如果是可变对象,程序运行会有逻辑错误。#错误示例:使用可变对象deffunc(a,b=[]):#❌列表是可变对象b.append(a)returnb#正确示例:使用不可变对象deffunc(a,b=None):#✓None是不可变对象ifbisNone:b=[]02/VARIABLEPARAMETERS可变参数的概念问题场景给定一组数字a,b,c……,请计算a+b+c+……。要定义这个函数,我们必须要确定输入的参数,但是该题中参数个数不确定。传统思路:把a,b,c……作为一个list或tuple传进来。传统实现方式#使用列表作为参数defcalc(numbers):s=0forninnumbers:s=s+nreturns#调用时需要传入列表calc([1,3,4])#结果:8calc([1,2,5,7])#结果:15calc([])#结果:0可变参数解决方案Python允许我们在定义的list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去。#使用可变参数defcalc(*numbers):s=0forninnumbers:s=s+nreturnscalc(1,3,4)→直接传入数字,结果:8calc(1,2,5,7)→传入4个数字,结果:15calc()→不传参数,结果:0优势:调用更加简洁,无需创建列表,直接传入任意数量的参数!02/IMPLEMENTATION可变参数的两种实现方式方式一:列表/元组传参defcalc(numbers):s=0forninnumbers:s=s+nreturns调用:calc([1,2,3])特点:需要先创建列表,再传入缺点•调用时需要额外创建列表•代码不够简洁•已有列表需要包装方式二:*可变参数defcalc(*numbers):s=0forninnumbers:s=s+nreturns调用:calc(1,2,3)特点:直接传入任意数量的参数优点•调用简洁,无需创建列表•支持任意数量的参数•代码更加Pythonic内部机制:使用*numbers时,传入的参数会被封装成一个tuple(元组),函数内部通过遍历这个元组来处理所有参数。如果已经有一个list或tuple,可以在调用时前面加*号,将其元素作为可变参数传入:calc(*[1,2,3])02/KEYWORDPARAMETERS关键字参数详解概念介绍Python函数中的关键字参数允许我们传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict(字典)。作用:可以扩展函数的功能,我们保证能接受到必选参数,但是也可以收到其它参数。语法格式#使用**表示关键字参数defstudent(name,age,**other):print('name:',name,'age:',age,'other:',other)name,age→必选参数**other→关键字参数(字典形式)调用示例#只传入必选参数student('XiaoMing',20)#传入一个关键字参数student('XiaoMing',20,sex='M')#传入多个关键字参数student('XiaoMing',20,sex='M',num='120153703')输出1:name:XiaoMingage:20other:{}输出2:name:XiaoMingage:20other:{'sex':'M'}输出3:name:XiaoMingage:20other:{'sex':'M','num':'120153703'}特点:关键字参数在函数内部被组装成字典,可以灵活接收任意数量的额外信息!02/APPLICATION关键字参数的实际应用综合示例defexample_function(a,b,*args,**kwargs):print(f"a:{a},b:{b}")print(f"额外位置参数:{args}")print(f"额外关键字参数:{kwargs}")#调用函数example_function(1,2,3,4,5,x=10,y=20)输出结果a:1,b:2额外位置参数:(3,4,5)额外关键字参数:{'x':10,'y':20}参数解析aa=1第一个必选参数bb=2第二个必选参数*args=(3,4,5)可变参数(元组)**kwargs={'x':10,'y':20}关键字参数(字典)应用场景:关键字参数非常适合用于扩展函数功能、接收配置选项、处理可选信息等场景,使函数接口更加灵活强大。02/PARAMETERCOMBINATION参数组合综合示例学生信息录入函数defregister_student(name,age,gender="未知",*courses,**other_info):"""参数说明:-name:必选参数(学生姓名)-age:必选参数(学生年龄)-gender:默认参数(默认值为"未知")-*courses:可变参数(接收选修课程)-**other_info:关键字参数(接收附加信息)"""print("\n---学生信息---")print(f"姓名:{name}")print(f"年龄:{age}")print(f"性别:{gender}")ifcourses:print("选修课程:",",".join(courses))ifother_info:print("其他信息:")forkey,valueinother_info.items():print(f"{key}:{value}")调用示例#仅必选参数register_student("张三",20)#必选+默认+可变register_student("李四",22,"男","数学","物理")#全部参数register_student("王五",25,"女","化学","生物",phone="123456",address="北京")输出结果调用1:张三性别:未知调用2:李四性别:男|课程:数学,物理调用3:王五性别:女|课程:化学,生物|phone:12345602/PARAMETERORDER参数定义的顺序规则必须遵循的顺序1必选参数调用时必须传入的参数,位置最靠前2默认参数有默认值的参数,可以省略不传3可变参数接收任意数量的位置参数4关键字参数接收任意数量的关键字参数正确示例#正确的参数顺序deffunc(a,b,c=3,*args,**kwargs):pass#调用func(1,2)func(1,2,4)func(1,2,4,5,6)func(1,2,4,5,6,x=7,y=8)错误示例#错误的参数顺序deffunc(*args,a,b,c=3,**kwargs):#❌可变参数不能在最前面deffunc(a,b,**kwargs,*args):#❌关键字参数不能在可变参数前面SyntaxError参数顺序错误会导致语法错误,Python解释器无法正确解析参数。记忆口诀:必(必选)→默(默认)→变(可变)→关(关键字)CHAPTER03高级函数特性探索函数嵌套、lambda表达式与递归调用掌握Python函数的高级用法与设计技巧AdvancedFeatures03/NESTEDFUNCTIONS函数嵌套的概念什么是函数嵌套嵌套函数的意思就是函数里边套函数,即在一个函数里边,再定义一个函数。内部函数定义在其它函数内的函数外部函数包含内部函数的函数基本语法defouter_function(params):#外部函数代码definner_function(params):#内部函数代码returnresult#调用内部函数result=inner_function(args)returnresult应用场景封装辅助功能将只在特定函数内部使用的辅助功能封装为内部函数,避免污染全局命名空间。闭包实现内部函数可以访问外部函数的变量,形成闭包,实现数据隐藏和状态保持。代码组织将复杂的逻辑拆分为多个小函数,提高代码的可读性和可维护性。递归辅助在递归函数中定义辅助函数来处理特定的子任务。03/EXECUTIONFLOW函数嵌套示例与执行流程示例代码defA(a):print('ThisisA')defB(b):print('ThisisB')print('a+b=',a+b)B(3)print('OVER!')#调用外部函数A(5)输出结果ThisisAThisisBa+b=8OVER!执行流程1调用A(5),传入a=52执行print('ThisisA')3定义内部函数B(b)4调用B(3),传入b=35B函数执行,输出结果6返回A函数,输出OVER!关键点:内部函数B可以访问外部函数A的变量a,这是闭包的基础特性。内部函数只在定义它的外部函数内部有效,外部无法直接访问。03/LAMBDAEXPRESSIONlambda表达式简介什么是lambda使用lambda语句可以创建表达式形式的匿名函数,即没有函数名的函数。语法格式lambdaargs:expression基本示例#定义lambda函数a=lambdax,y:x+y#调用r=a(2,3)#r的值为5print(r)#输出:5说明:args是以逗号分隔的参数列表,expression是用到这些参数的表达式。主要用途指定回调函数lambda的首要用途是指定短小的回调函数。#对大小写敏感的名称排序names.sort(key=lambdan:n.lower())配合高阶函数与map、filter、reduce等高阶函数配合使用。#使用map函数list(map(lambdax:x**2,[1,2,3]))#[1,4,9]简化代码对于简单的函数,使用lambda可以使代码更加简洁。03/LIMITATIONSlambda表达式的使用限制必须是合法表达式使用lambda语句定义的代码必须是合法的表达式。#正确:表达式lambdax:x+1#✓#错误:赋值语句lambdax:x=1#❌SyntaxError不能包含多条语句lambda语句中不能出现多条语句和其它非表达式语句。#错误:多条语句lambdax:print(x);print(x)#❌#错误:控制流语句lambdax:foriinx:print(i)#❌SyntaxError遵循作用域规则lambda表达式遵循与函数相同的作用域规则。x=10f=lambday:x+yprint(f(5))#输出:15lambda可以访问外部变量,遵循LEGB作用域规则。使用建议适用于简单的、一次性的函数逻辑复杂时应使用def定义函数保持代码的可读性和可维护性总结:lambda表达式虽然简洁,但功能有限。对于复杂的逻辑,应该使用def定义普通函数,以保证代码的可读性和可维护性。03/PRACTICALAPPLICATIONlambda表达式的实际应用排序应用对一列大小写敏感的名称进行排序,使用lambda指定排序关键字。#原始列表names=['Alice','bob','Charlie','david']#使用lambda排序(忽略大小写)names.sort(key=lambdan:n.lower())print(names)#输出:['Alice','bob','Charlie','david']原理:lambda函数将每个元素转换为小写后再进行比较。配合map函数#对列表每个元素求平方numbers=[1,2,3,4,5]squared=list(map(lambdax:x**2,numbers))print(squared)#输出:[1,4,9,16,25]配合filter函数#过滤出偶数numbers=[1,2,3,4,5,6]evens=list(filter(lambdax:x%2==0,numbers))print(evens)#输出:[2,4,6]数据处理#字典列表排序students=[{'name':'Alice','score':85},{'name':'Bob','score':92},{'name':'Charlie','score':78}]#按成绩排序students.sort(key=lambdas:s['score'],reverse=True)结果:[{'name':'Bob','score':92},{'name':'Alice','score':85},{'name':'Charlie','score':78}]最佳实践:lambda表达式最适合用于简单、一次性的操作场景,配合高阶函数使用可以大大简化代码。03/RECURSIVEFUNCTION递归函数的概念什么是递归"递归"过程是指函数直接或间接调用自身完成某任务的过程。直接递归函数中直接调用函数自身间接递归函数A调用函数B,函数B再调用函数A递归的基本结构defrecursive_func(n):#1.终止条件(基准情况)ifn<=1:return1#2.递归调用(向终止条件靠近)returnn*recursive_func(n-1)递归的核心思想递推过程将大问题分解为相似的子问题,不断调用自身,直到达到终止条件。回归过程从终止条件开始,逐层返回结果,最终得到原问题的解。类比理解就像俄罗斯套娃,每个娃娃里面都有一个更小的自己,直到最小的那个。注意:递归必须有终止条件,否则会导致无限递归,最终栈溢出。03/FACTORIALEXAMPLE递归示例:阶乘计算阶乘函数实现deffac(n):ifn<=1:return1else:returnn*fac(n-1)#调用print(fac(4))#输出:24数学定义n!=n×(n-1)!1!=1(终止条件)执行过程(n=4)递推阶段①fac(4)=4×fac(3)②fac(3)=3×fac(2)③fac(2)=2×fac(1)④fac(1)=1✓终止回归阶段⑤fac(2)=2×1=2⑥fac(3)=3×2=6⑦fac(4)=4×6=24调用栈示意fac(4)↓fac(3)↓fac(2)↓fac(1)=103/RECURSIVECONDITIONS递归的两个必要条件1终止条件给出递归终止的条件和相应的状态。阶乘示例终止条件:n=1状态:fac(1)=1ifn<=1:return1#终止条件没有终止条件会导致无限递归!2递归表达式给出递归的表述形式,并且要向着终止条件变化,在有限步骤内达到终止条件。阶乘示例当n>1时:fac(n)=n×fac(n-1)参数变化:n→n-1(向终止条件靠近)returnn*fac(n-1)#递归表达式每次递归都要向终止条件靠近!设计递归函数的关键:1.找到终止条件;2.找到递归关系;3.确保收敛性(每次调用都向终止条件靠近)03/DIRECTORYTRAVERSAL递归应用:目录遍历完整代码

importosdeflist_files(path):#遍历目录中的所有文件和子目录forfileinos.listdir(path):full_path=os.path.join(path,file)#如果是目录,递归遍历ifos.path.isdir(full_path):list_files(full_path)else:#如果是文件,打印路径print(full_path)#列出当前目录下所有文件list_files("./")工作原理①遍历当前目录使用os.listdir()获取目录中的所有项②判断文件类型使用os.path.isdir()判断是否为目录③递归处理子目录如果是目录,递归调用list_files()④输出文件路径如果是文件,打印完整路径目录结构示例project/├──main.py├──utils/│├──helper.py│└──config.py└──data/└──input.txt递归遍历会输出所有文件的完整路径递归的优势:处理树形结构、嵌套数据等问题时,递归代码往往比迭代代码更加简洁优雅。04变量作用域理解局部变量与全局变量的作用范围掌握变量访问规则与作用域管理VariableScope04/VARIABLESCOPE局部变量与全局变量局部变量在函数中定义的变量称为局部变量。局部变量只在定义它的函数内部有效。特点•只在函数内部可见•函数执行完毕后销毁•不同函数的局部变量互不影响deffunc():x=10#局部变量print(x)#可以访问func()print(x)#❌错误!外部无法访问全局变量在函数体之外定义的变量称为全局变量。全局变量在定义之后的代码中都有效。特点•在整个模块中可见•包括其后定义的函数体内•程序运行期间一直存在x=10#全局变量deffunc():print(x)#✓可以访问全局变量func()print(x)#✓也可以访问注意:如果局部变量和全局变量重名,则在定义局部变量的函数中,只有局部变量是有效的。04/SCOPEEXAMPLE变量作用域示例分析示例代码#全局变量a=20defsetNumber():#局部变量(与全局变量同名)a=55b=12#局部变量print(a)#输出局部变量aa=a+1print(a)#输出修改后的局部变量aprint(b)#输出局部变量bsetNumber()print(a)#输出全局变量aprint(b)#❌错误!b是局部变量输出结果55#setNumber()中的局部变量a56#修改后的局部变量a12#局部变量b20#全局变量a(未被修改)#NameError:name'b'isnotdefined详细分析全局变量a第1行定义,值为20。在setNumber()中被局部变量a"遮蔽",函数内无法直接访问。局部变量a函数内定义,初始值55。修改只影响局部变量,不影响全局变量a。局部变量b只在函数内部有效,函数外部访问会报NameError。04/SCOPERULES作用域规则总结局部变量规则规则1局部变量只在定义它的函数内部有效规则2函数执行完毕后,局部变量自动销毁规则3不同函数的局部变量互不影响全局变量规则规则1全局变量在定义之后的代码中都有效规则2包括其后定义的函数体内也可以访问规则3程序运行期间一直存在同名变量规则如果局部变量和全局变量重名,则在定义局部变量的函数中,只有局部变量是有效的。这称为变量的"遮蔽"(Shadowing)现象。最佳实践:尽量避免局部变量与全局变量同名,使用不同的命名来区分,提高代码可读性。05模块与包掌握模块化编程的核心技术理解模块的创建、导入与包的组织管理Modules&Packages05/MODULECONCEPT模块的概念与优势什么是模块为了编写可维护的代码,我们把一个大的系统分别放到不同的文件里。在Python中,一个.py文件就称之为一个模块(Module)。类比理解:就像一本书的章节,每个模块负责一个独立的功能。模块命名模块名=文件名(不含.py)如:test.py→模块名为test#test.py文件defadd(a,b):returna+bdefsub(a,b):returna-b使用模块的优势提高可维护性每个文件包含的代码相对较少,便于管理和维护。当模块编写完毕,可以被其它地方引用。代码复用在写程序的时候,经常引用其它模块。模块可以被多个程序共享使用,避免重复开发。避免命名冲突相同名字的函数和变量完全可以分别存在于不同的模块中,避免命名冲突。注意:尽量不要与内置函数名字冲突,编写模块时考虑命名空间。05/IMPORTMODULE模块的导入方式(一)import语句在Python中使用关键字import来引入某个模块。语法格式importmodule1[,module2[,...moduleN]]#导入单个模块importmath#导入多个模块importos,sys,datetime调用方式在调用math模块中的函数时,必须这样引用:模块名.函数名importmath#正确调用print(math.sqrt(4))#输出:2.0#错误调用print(sqrt(4))#❌NameError为什么必须加模块名?因为可能存在多个模块中含有相同名称的函数,通过模块名可以明确指定调用哪个函数。实际示例math模块importmath#计算平方根print(math.sqrt(16))#4.0#计算阶乘print(math.factorial(5))#120#获取圆周率print(math.pi)#3.14159...random模块importrandom#生成随机整数print(random.randint(1,10))#随机选择print(random.choice(['A','B','C']))05/FROMIMPORT模块的导入方式(二)from...import语句如果只需要用到模块中的某个函数,可以通过from...import语句只引入该函数。语法格式frommodnameimportname1[,name2[,...nameN]]#导入单个函数frommathimportsqrt#导入多个函数frommathimportsqrt,pow,factorial调用方式通过这种方式引入时,调用函数时只能给出函数名,不能给出模块名。frommathimportsqrt#直接调用,无需模块名print(sqrt(4))#输出:2.0注意:当两个模块中含有相同名称函数时,后面一次引入会覆盖前一次引入。覆盖问题#模块A中有function()frommoduleAimportfunction#模块B中也有function()frommoduleBimportfunction#此时调用function()执行的是模块B中的函数function()#执行moduleB.function()from...import*如果想一次性引入模块中所有的东西,可以使用frommoduleimport*。frommathimport*#可以直接使用所有函数print(sqrt(4))print(pi)print(factorial(5))⚠️不建议使用可能引入命名冲突,降低代码可读性。只在交互式解释器中使用。05/CUSTOMMODULE创建自定义模块创建模块在Python中,每个Python文件都可以作为一个模块,模块的名字就是文件的名字。步骤1:创建模块文件创建test.py文件,定义函数:#test.pydefadd(a,b):returna+bdefsub(a,b):returna-b步骤2:在其他文件中使用#test1.pyimporttestprint(test.add(3,4))#输出:7使用from...import#导入特定函数fromtestimportadd#直接调用print(add(3,4))#输出:7使用from...import可以直接使用函数名,代码更简洁。模块设计建议模块名应见名知意,使用小写字母和下划线一个模块负责一类相关的功能避免与Python内置模块重名添加文档字符串说明模块功能05/EXECUTIONMECHANISM模块导入的执行机制导入时执行在用import引入模块时,会将引入的模块文件中的代码执行一次。#test.pydefdisplay():print("helloworld")display()#模块被导入时会执行#test1.pyimporttest#输出:helloworld只执行一次只在第一次引入时才会执行模块文件中的代码,因为只在第一次引入时进行加载。这样做可以节约时间还可以节约内存。__name__属性如果只想在模块自身运行时执行某些代码,可以使用__name__属性。#test.pyif__name__=='__main__':print('程序自身在运行')else:print('我是被引入')直接运行test.py输出:程序自身在运行在其他文件中importtest输出:我是被引入最佳实践:在模块中添加测试代码时,使用if__name__=='__main__':保护,避免被导入时执行。05/PACKAGECONCEPT模块包的概念什么是包包(Packages)是用来组织模块的一个目录。为了让Python把这个目录当做包,目录中的__init__.py文件是必须要有的。__init__.py的作用•标识一个目录为Python包•可以为包执行初始化语句•设置__all__变量控制导入•可以是空文件包的结构示例mypackage/├──__init__.py├──module1.py├──module2.py└──subpackage/├──__init__.py└──module3.py包的优势组织管理将相关的模块组织在一起,形成层次化的结构,便于管理和维护。命名空间包提供了命名空间,不同包中的模块可以有相同的名字而不会冲突。便于分发包可以作为整体进行分发和安装,方便共享和复用。扩展性可以在包中添加新的模块或子包,方便功能扩展。05/PACKAGEIMPORT包的导入方式完整路径导入使用importPackage.SubPackage.Module从包中导入单独的模块。#导入包中的模块importmypackage.module1#使用模块mypackage.module1.func()必须使用完整路径名来调用模块中的函数。简化导入方式#方式1:from...importfrommypackageimportmodule1module1.func()#方式2:直接导入函数frommypackage.module1importfuncfunc()简化方式可以直接使用模块名或函数名,无需完整路径。实际示例包结构mypackage/├──__init__.py├──mathutils.py└──stringutils.pymathutils.py内容defadd(a,b):returna+bdefmultiply(a,b):returna*b导入和使用frommypackageimportmathutilsprint(mathutils.add(2,3))#5print(mathutils.multiply(4,5))#2005/__ALL__VARIABLE__all__变量的作用什么是__all__如果包的__init__.py定义了一个名为__all__的列表变量,它包含的模块名字的列表将作为被导入的模块列表。作用控制frompackageimport*时导入哪些模块。定义__all__#mypackage/__init__.py#定义__all__变量__all__=['module1','module2']#可选:导入常用函数from.module1importfunc1from.module2importfunc2使用frommypackageimport*时,只会导入module1和module2。对比示例有__all__的情况#__init__.py__all__=['mathutils']frommypackageimport*#只导入mathutilsprint(mathutils.add(1,2))#✓#stringutils未导入#print(stringutils.upper("abc"))#❌无__all__的情况frommypackageimport*#只保证包被导入#不会自动导入所有子模块#需要显式导入importmypackage.mathutilsimportmypackage.stringutils建议:在包的__init__.py中定义__all__变量,明确指定哪些模块可以通过from...import*导入。CHAPTER06项目开发实践通过实际项目巩固所学知识掌握常用算法与综合应用开发ProjectDevelopment06/SEARCHALGORITHM查找算法:顺序查找算法原理从第一个元素开始逐一比较,直到找到目标元素或遍历完所有元素。算法步骤从数组的第一个元素开始将目标值与当前元素比较如果相等,返回找到如果不相等,继续下一个遍历完未找到,返回失败defsequential_search(a,n):pos=0found=Falsewhilepos<len(a)andnotfound:ifa[pos]==n:found=Trueelse:pos=pos+1returnfound使用示例a=[1,2,3,4,5,6,8,20,24,31,35]x=24print(sequential_search(a,x))#输出:True如果x=25,则输出False时间复杂度分析最好情况第一个就是要找的,1次比较最坏情况最后一个或找不到,n次比较平均情况平均比较n/2次06/BINARYSEARCH查找算法:折半查找算法原理折半查找(二分查找)要求数据已排序。每次将目标值与中间元素比较,缩小查找范围。算法步骤确定查找范围的底部和顶部计算中间位置目标值与中间元素比较相等则找到,返回位置小于则在前半部分继续大于则在后半部分继续重复直到找到或范围为空代码实现defbinary_search(a,n):low=0high=len(a)-1whilelow<=high:mid=(low+high)//2ifa[mid]==n:returnmid+1elifa[mid]<n:low=mid+1else:high=mid-1return-1print(binary_Search(a,x))执行过程示例a=[1,2,3,4,5,6,8,20,24,31,35]查找:24①low=0,high=10,mid=5,a[5]=6<24②low=6,high=10,mid=8,a[8]=24==24✓找到!位置:9(mid+1)时间复杂度时间复杂度O(logn)-对数级每次查找范围减半适用条件•数据必须已排序•适合大数据量查找优势比顺序查找快得多,n越大优势越明显06/SORTINGALGORITHMS排序算法:选择排序与冒泡排序选择排序每次从未排序部分选择最小的元素,放到已排序部分的末尾。defselection_sort(a):foriinrange(len(a)):min_idx=iforjinrange(i+1,len(a)):ifa[j]<a[min_idx]:min_idx=ja[i],a[min_idx]=a[min_idx],a[i]a=[0,70,20,10,30,40,50]selection_sort(a)print(a)#[0,10,20,30,40,50,70]时间复杂度:O(n²)|空间复杂度:O(1)冒泡排序重复遍历数组,比较相邻元素,如果顺序错误就交换,直到没有需要交换的元素。defbubble_sort(l):flag=Trueforiinrange(len(l)-1,0,-1):ifflag:flag

温馨提示

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

评论

0/150

提交评论