函数进阶与异常
本篇要点:① 函数基础回顾 ② 函数进阶(文档/嵌套/全局变量/多返回值/多种参数/匿名函数/递归) ③ 异常处理
大纲
- 函数基础(回顾)
- 函数进阶(说明文档、嵌套调用、全局/局部变量、多返回值、多种参数、匿名函数、递归)
- 异常(系统默认处理、try/except、else/finally、传递性)
一、函数基础【回顾】
函数核心知识点
properties
# 通用定义格式
def 函数名(形参):
函数体
return 返回值
# 通用调用格式
变量 = 函数名(实参)
# 注意事项
1. 函数必须先定义,再调用
2. 函数不调用不执行
3. 函数每调用1次就执行1次
4. 定义函数的时候如果有形参,调用函数的时候就必须传入实参
5. 定义函数的时候有return返回值,调用时建议使用变量接收返回值后再使用
6. 定义函数的时候没有return返回值,其实默认函数最后一行补充了return None三种基本函数形态
python
# 1.无参无返回值
def qiu_he():
a = 10
b = 20
he = a + b
print(he)
qiu_he()
# 2.有参无返回值
def qiu_he(a, b):
he = a + b
print(he)
qiu_he(10, 20)
# 3.有参有返回值
def qiu_he(a, b):
he = a + b
return he
h1 = qiu_he(10, 20)
print(h1)二、函数进阶
函数说明文档
python
"""
函数说明文档: 本质就是多行注释,只是位置在函数内的函数体之前
"""
def qiu_he(a, b):
"""
功能: 求两个数的和
:param a: 整数
:param b: 整数
:return: 整数
"""
he = a + b
return he函数嵌套调用
python
def test1():
print('-------test1 开始--------')
print('此处省略1w行代码~')
print('-------test1 结束--------')
def test2():
print('-------test2 开始--------')
test1() # 在函数中调用另一个函数
print('-------test2 结束--------')
# main: 程序的入口
if __name__ == '__main__':
print('--------main 开始 -------')
test2()
print('--------main 结束 -------')全局变量和局部变量
properties
局部变量: 位置: 自定义函数内定义 范围: 只能在函数内使用
全局变量: 位置: 自定义函数外定义 范围: 在函数内外都能使用
局部变量和全局变量同名问题: 在自定义函数内会根据就近原则,优先使用局部变量
在函数内想修改全局变量: 正常修改操作默认会创建一个和全局变量同名的局部变量,
必须使用global声明接下来的操作是修改全局变量,才能真正修改全局变量python
def test1():
a = 10 # 局部变量,只能在test1中访问
print(a)
print(num) # 全局变量,函数内外都能访问
def test2():
print(num) # 全局变量,函数内外都能访问
if __name__ == '__main__':
num = 100 # 全局变量
test1()
test2()就近原则和 global 关键字
python
def test1():
num = 10 # 局部变量和全局变量同名,默认按就近原则打印局部变量
print(num) # 10
def test2():
global num # 声明修改的是全局变量
num = 200
print(num)
if __name__ == '__main__':
num = 100
test1() # 10
test2() # 200
print(num) # 200 (全局变量已被修改)自定义自己的 len 函数
python
def my_len(my_str):
count = 0
for i in my_str:
count += 1
return count
s = input('请您输入一个字符串,我帮您计算长度:')
cd = my_len(s)
print(f"您输入的字符串长度为:{cd}")多返回值
properties
return的作用: 1.结束当前函数 2.顺带把return后面的返回值返回给调用者
return x,y,z...: 默认把x,y,z...封装到元组中,然后元组返回给调用者python
def show():
return 1, 2, 3, 4, 5 # 默认多个值用元组打包
result = show()
print(result, type(result)) # (1, 2, 3, 4, 5)
a, b, c, d, e = result # 拆包
print(a, b, c, d, e)多种参数
properties
位置参数: 实参和形参的个数以及顺序都必须一致
关键字参数: 实参和形参的顺序可以不一致,但是个数必须一致(形参变量名=实参值)
缺省参数: 在定义函数时,形参位置直接设置默认值,调用时实参可以不传直接用默认值
可变参数:
*args: 默认把位置传参进来的数据放到args元组中
**kwargs: 默认把关键字传参进来的数据放到kwargs字典中python
# 1.位置参数 / 关键字参数 / 缺省参数
def show(name, age=18, height=188.8): # 位置参数必须在前,缺省参数在后
print(f"{age}岁的{name},身高是{height}厘米")
show('张三', 18, 178.8) # 位置传参
show(name='张三', age=18, height=178.8) # 关键字传参
show('张三', age=18, height=178.8) # 混合传参: 位置在前
show('张三') # 缺省参数不传直接用默认值
# 2.可变参数
def show1(*args):
print(args, type(args)) # 元组
def show2(**kwargs):
print(kwargs, type(kwargs)) # 字典
show1(1, 2, 3)
show2(a=1, b=2, c=3)练习:用 *args 和 **kwargs 求所有传入数字的和:
python
def get_sum(*args, **kwargs):
sum = 0
for i in args:
sum += i
for i in kwargs.values():
sum += i
return sum
h = get_sum(1, 2, 3, 4, a=5, b=6)
print(h) # 21匿名函数(lambda)
properties
lambda表达式: 简单函数的简洁写法,它又叫匿名函数。
语法形式: lambda 形参1, 形参2, ... : 单行表达式 或 函数调用
注意点:
1) 匿名函数中不能使用while循环、for循环,只能编写单行的表达式或函数调用
2) 匿名函数中返回结果不需要使用return,表达式的运行结果就是返回结果
3) 匿名函数中也可以不返回结果。例如: lambda : print('hello world')python
# 1.入门示例
def get_sum(a, b):
return a + b
print(get_sum(1, 2)) # 原始方式
print((lambda a, b: a + b)(1, 2)) # 匿名函数方式
# 2.引用地址传递(函数作为参数传递)
def get_sum(a, b):
return a + b
def show(func, a, b): # 接收一个函数名作为参数,内部调用
result = func(a, b)
print(result)
show(get_sum, 10, 2) # 传原生函数名
show(lambda a, b: a + b, 10, 2) # 传lambda表达式
show(lambda a, b: a * b, 10, 2)
show(lambda a, b: a ** b, 10, 2) # lambda传参更方便递归函数
properties
递归: 就是某个函数直接或者间接地调用自身的一种设计程序思想,
原问题的求解就转换为了许多性质相同但是规模更小的子问题。
应用场景:
① 实现复杂的数学计算,如斐波那契数列,求汉诺塔
② 实现文件递归查询,递归查询某个目录以及子目录下的所有文件
递归三要素:
① 明确你这个函数想要干什么(先不管函数里面的代码,先明白函数是用来干什么)
② 寻找递归结束条件(找出当参数为啥时,递归结束,直接返回结果)
③ 找出函数的等价关系式(不断缩小参数范围,通过辅助变量或操作,使原函数结果不变)求和示例(递归求 1 到 5 的和)
python
def get_sum(x):
if x == 1: # 2.结束条件
return 1
return x + get_sum(x - 1) # 3.等价关系式
he = get_sum(5)
print(he) # 15求阶乘示例
python
def get_f(x):
if x in (1, 2): # 2.结束条件
return x
return x * get_f(x - 1) # 3.等价关系式
he = get_f(5)
print(he) # 120不死神兔【了解】
假设 1 对小兔,一个月长成大兔,再过一个月就生一对小兔……假设没有死亡,一年后有多少对? 月份:1月1对、2月1对、3月2对、4月3对、5月5对……(斐波那契数列)
python
def get_rabbits(month):
if month in (2, 1): # 2.结束条件
return 1
return get_rabbits(month - 1) + get_rabbits(month - 2)
print(get_rabbits(12))三、异常
系统默认处理异常方式
properties
系统默认处理异常的方式: 就是在异常位置直接中断程序,后面的代码就无法执行了python
print('程序开始~')
# NameError异常: 变量名没有提前定义过
print(a)
# FileNotFoundError异常: 打开文件时,模式如果是r,此文件不存在就报错
f = open('a.txt', 'r')
# ZeroDivisionError异常: 除法运算时,0不能作为除数
print(1/0)
print('程序结束~') # 无法执行到try / except 处理异常
properties
try:
可能出现异常的代码
except Exception as e:
出现异常要执行的代码python
print('程序开始~')
try:
print(a)
print(1 / 0)
except Exception as e:
print(f'报错了吧:{e},下回注意啊~,接着去工作吧')
print('程序结束~')try / except / else / finally 处理异常
properties
try:
可能出现异常的代码
except Exception as e:
出现异常要执行的代码
else:
没有异常执行的代码
finally:
不管有没有异常都要执行的代码python
try:
print(a)
print('此处省略1w行代码')
except Exception as e:
print('except中是有异常执行的代码')
else:
print('else中是没有异常执行的代码')
finally:
print('finally中是不管有没有异常都执行的代码')异常具有传递性
python
def show1():
print('--------show1开始---------')
try: # 异常建议在根源解决
print(1 / 0)
except Exception as e:
print(e)
print('--------show1结束---------')
def show2():
print('--------show2开始---------')
show1() # 异常会在函数调用链中传递
print('--------show2结束---------')
if __name__ == '__main__':
print('程序开始~')
show2()
print('程序结束~')