Skip to content

函数进阶与异常

函数进阶与异常

本篇要点:① 函数基础回顾 ② 函数进阶(文档/嵌套/全局变量/多返回值/多种参数/匿名函数/递归) ③ 异常处理


大纲

  1. 函数基础(回顾)
  2. 函数进阶(说明文档、嵌套调用、全局/局部变量、多返回值、多种参数、匿名函数、递归)
  3. 异常(系统默认处理、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('程序结束~')

基于 VitePress 构建 · 专注前端与 AI 实战