当前位置:首页>python>学习python第三周——函数(一)定义与调用

学习python第三周——函数(一)定义与调用

  • 2026-09-02 15:58:10
学习python第三周——函数(一)定义与调用

本期目标

  • 理解“函数”的概念和意义——为什么要用函数
  • 掌握函数的定义与调用语法
  • 学会使用位置参数、关键字参数、默认参数
  • 理解函数的返回值(return)和作用域
  • 完成实战项目:常用数学工具函数库

一、为什么需要函数?

回顾前几期,我们写了不少代码:统计成绩、词频统计……这些代码虽然能运行,但存在一个共同问题:如果你想重复使用某段逻辑,就必须复制粘贴。这不仅让代码变得臃肿,还容易出错——如果逻辑需要修改,你得在所有复制的地方一一修改。

举个例子,假设你需要多次计算圆的面积:

1
2
3
4
5
6
7
8
9
10
11
# 第一次计算r1 = 5area1 = 3.14159 * r1 ** 2print(area1)# 第二次计算(又写一遍)r2 = 7area2 = 3.14159 * r2 ** 2print(area2)# 第三次…… 如果要求改 π 的精度,所有地方都要改

这样的代码很“笨拙”。但如果用函数,你就可以把这段逻辑“封装”起来,给它起个名字,需要的时候“调用”一下即可:

1
2
3
4
5
6
7
def calc_circle_area(radius):    pi = 3.14159    return pi * radius ** 2# 需要时直接调用print(calc_circle_area(5))   # 78.53975print(calc_circle_area(7))   # 153.93791

函数的核心价值在于:

  1. 代码复用: 一次定义,多次调用
  2. 模块化: 把复杂问题拆分成小模块,每个函数只做一件事
  3. 易于维护: 修改函数内部逻辑,所有调用处自动生效
  4. 可读性强: 好的函数名就像注释,一看就知道功能

在AI领域,函数更是无处不在:

  • 数据预处理函数: load_data()、clean_data()、normalize()
  • 模型构建函数: build_model()、train_model()、evaluate()
  • 工具函数: plot_accuracy()、save_checkpoint()

二、函数的定义与调用

1. 基本语法

Python 使用 def 关键字定义函数,基本结构如下:

1
2
3
4
def 函数名(参数1, 参数2, ...):    """文档字符串(可选,描述函数功能)"""    函数体代码    return 返回值   # 可选

示例:一个最简单的函数

1
2
3
4
5
6
7
# 定义函数def say_hello():    """打印问候语"""    print("Hello, AI World!")# 调用函数say_hello()   # 输出:Hello, AI World!

⚠️ 注意:定义函数只是“声明”了它,并不会执行函数体内的代码。只有当你“调用”函数(写上函数名加括号)时,代码才会运行。

2. 带参数的函数

函数可以接收输入数据(参数),让功能更灵活:

1
2
3
4
5
6
def greet(name):    """向指定的人打招呼"""    print(f"你好,{name}!")greet("张三")   # 你好,张三!greet("李四")   # 你好,李四!

3. 带返回值的函数(return)

return 语句用于将函数的结果“返回”给调用者。一旦执行 return,函数立即结束。

1
2
3
4
5
6
def add(a, b):    """返回两个数的和"""    return a + bresult = add(3, 5)   # result 接收返回值print(result)        # 8

没有 return 的函数默认返回 None:

1
2
3
4
5
def do_nothing():    pass   # pass 是空语句,占位用val = do_nothing()print(val)   # None

4. 参数与返回值的灵活组合

  • 无参数无返回值: 执行某些操作(如打印菜单)
  • 有参数无返回值: 处理数据但不返回(如打印统计信息)
  • 无参数有返回值: 获取某些数据(如获取当前时间)
  • 有参数有返回值: 最常用,计算并返回结果

三、函数的参数详解

1. 位置参数(Positional Arguments)

调用函数时,传入的参数按位置依次赋值给形参:

1
2
3
4
5
def introduce(name, age, city):    print(f"{name},{age}岁,来自{city}")introduce("张三", 20, "北京")   # 张三,20岁,来自北京introduce("李四", 25, "上海")   # 李四,25岁,来自上海

顺序必须一一对应,否则会出错或逻辑混乱。

2. 关键字参数(Keyword Arguments)

调用时可以通过“参数名=值”的方式传递,顺序可以打乱:

1
introduce(age=20, city="北京", name="张三")   # 正确,顺序无关

关键字参数提高了代码可读性,尤其在参数较多时非常有用。

3. 默认参数(Default Arguments)

定义函数时可以为参数指定默认值,调用时如果不传该参数,则使用默认值:

1
2
3
4
5
def greet(name, greeting="你好"):    print(f"{greeting},{name}!")greet("张三")              # 你好,张三!greet("李四", "Hello")     # Hello,李四!

⚠️ 重要规则:默认参数必须放在所有没有默认值的参数之后,否则会报错。

1
2
3
4
5
6
7
# ❌ 错误def greet(greeting="你好", name):<br>    ...# ✅ 正确def greet(name, greeting="你好"):<br>    ...、

💡 小贴士:默认参数在AI中常用于配置函数,比如 train_model(data, lr=0.001, epochs=100),大部分情况下使用默认值即可,但需要调参时可以灵活覆盖。

4. 可变参数(*args 和 **kwargs)——了解即可,下期扩展

Python 还支持接收任意数量的位置参数(*args)和关键字参数(**kwargs),我们在下期会详细讲解。

四、作用域(Scope)——变量的可见范围

1. 局部变量 vs 全局变量

  • 局部变量: 在函数内部定义的变量,只能在该函数内使用
  • 全局变量: 在函数外部定义的变量,可以在整个程序中访问(但函数内部如需修改,需要 global 声明)
1
2
3
4
5
6
7
8
9
10
11
# 全局变量x = 10def test():    y = 5          # 局部变量    print(x)       # 可以访问全局变量 x(只读)    print(y)test()             # 10, 5print(x)           # 10(全局变量仍然存在)# print(y)         # ❌ NameError:y 在函数外部不可见

在函数内部修改全局变量(不推荐,容易造成混乱):

1
2
3
4
5
6
7
8
x = 10def change_global():    global x   # 声明要修改全局变量 x    x = 20change_global()print(x)   # 20

⚠️ 最佳实践:尽量避免在函数内部修改全局变量。如果需要修改,可以通过返回值的方式实现,保持函数“纯粹性”。

2. 变量查找规则(LEGB)

Python 查找变量的顺序是:Local(局部)→ Enclosing(外层函数)→ Global(全局)→ Built-in(内置)。这个概念在嵌套函数中会用到,目前只需记住:函数内部优先使用局部变量。

五、实战项目:常用数学工具函数库

现在,我们利用函数把之前分散的数学计算整理成一个工具库,方便以后复用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# ============================================# 数学工具函数库(math_utils.py)# 包含:阶乘、斐波那契数列、质数判断、最大公约数、最小公倍数# ============================================def factorial(n):    """    计算 n 的阶乘(n!)    例如:5! = 5*4*3*2*1 = 120    """    if n < 0:        return None   # 负数没有阶乘    result = 1    for i in range(2, n + 1):        result *= i    return resultdef fibonacci(n):    """    生成斐波那契数列的前 n 项(列表形式)    斐波那契:第1项=0,第2项=1,之后每一项是前两项之和    """    if n <= 0:        return []    elif n == 1:        return [0]    elif n == 2:        return [0, 1]    else:        seq = [0, 1]        for i in range(2, n):            seq.append(seq[-1] + seq[-2])        return seqdef is_prime(num):    """    判断一个正整数是否为质数(只能被1和自身整除)    """    if num < 2:        return False    # 只需检查到 sqrt(num) 即可    for i in range(2, int(num ** 0.5) + 1):        if num % i == 0:            return False    return Truedef gcd(a, b):    """    计算 a 和 b 的最大公约数(欧几里得算法)    """    while b != 0:        a, b = b, a % b    return adef lcm(a, b):    """    计算 a 和 b 的最小公倍数    公式:a * b / gcd(a, b)    """    return a * b // gcd(a, b)# ========== 测试函数 ==========if __name__ == "__main__":    print("===== 数学工具库测试 =====")    # 阶乘    print(f"5! = {factorial(5)}")          # 120    print(f"0! = {factorial(0)}")          # 1    # 斐波那契    print(f"前10项斐波那契:{fibonacci(10)}")    # 质数判断    print(f"17是质数吗?{is_prime(17)}")   # True    print(f"20是质数吗?{is_prime(20)}")   # False    # 最大公约数    print(f"48和36的最大公约数:{gcd(48, 36)}")  # 12    # 最小公倍数    print(f"12和18的最小公倍数:{lcm(12, 18)}")  # 36

运行效果:

1
2
3
4
5
6
7
8
===== 数学工具库测试 =====5! = 1200! = 1前10项斐波那契:[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]17是质数吗?True20是质数吗?False48和36的最大公约数:1212和18的最小公倍数:36

实战扩展:用户交互式数学工具

我们可以再写一个交互式程序,让用户选择使用哪个工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def show_math_menu():    """显示数学工具菜单"""    print("\n" + "=" * 40)    print("      🔢 数学工具库")    print("=" * 40)    print("  1. 计算阶乘")    print("  2. 生成斐波那契数列")    print("  3. 判断质数")    print("  4. 计算最大公约数")    print("  5. 计算最小公倍数")    print("  6. 退出")    print("=" * 40)def math_tool():    """主交互程序"""    while True:        show_math_menu()        choice = input("请选择功能 (1-6):")        if choice == "1":            n = int(input("请输入一个非负整数:"))            result = factorial(n)            print(f"{n}! = {result}")        elif choice == "2":            n = int(input("请输入项数:"))            result = fibonacci(n)            print(f"前{n}项:{result}")        elif choice == "3":            n = int(input("请输入一个正整数:"))            result = is_prime(n)            print(f"{n} {'是' if result else '不是'}质数")        elif choice == "4":            a = int(input("请输入第一个数:"))            b = int(input("请输入第二个数:"))            result = gcd(a, b)            print(f"最大公约数:{result}")        elif choice == "5":            a = int(input("请输入第一个数:"))            b = int(input("请输入第二个数:"))            result = lcm(a, b)            print(f"最小公倍数:{result}")        elif choice == "6":            print("👋 感谢使用,再见!")            break        else:            print("❌ 无效选择,请重新输入!")# 启动工具if __name__ == "__main__":    math_tool()

效果展示:

效果展示

六、动手练习

练习1:定义简单函数

编写一个函数 is_even(num),接收一个整数,如果它是偶数返回 True,否则返回 False。

👆 点击查看参考答案
1
2
3
4
5
def is_even(num):    return num % 2 == 0print(is_even(4))   # Trueprint(is_even(7))   # False

练习2:默认参数的应用

编写一个函数 create_user(name, age=18, city="未知"),打印用户信息。调用时分别传入不同参数验证。

👆 点击查看参考答案
1
2
3
4
5
6
def create_user(name, age=18, city="未知"):    print(f"用户:{name},年龄:{age},城市:{city}")create_user("张三")                # 用户:张三,年龄:18,城市:未知create_user("李四", 25)            # 用户:李四,年龄:25,城市:未知create_user("王五", 30, "北京")    # 用户:王五,年龄:30,城市:北京

练习3:作用域理解

分析以下代码,写出输出结果,并解释为什么:

1
2
3
4
5
6
7
8
9
10
x = 100def outer():    x = 200    def inner():        print(x)    inner()outer()print(x)
👆 点击查看参考答案
1
2
3
4
# 输出:# 200# 100# 解释:outer 内部定义了局部变量 x=200,inner 打印的 x 是 outer 的局部变量(闭包),所以是 200。outer 外部的全局 x 未受影响,仍为 100。

本期小结

本期我们迈入了“模块化编程”的大门:

知识点
核心要点
函数定义def 函数名(参数):
 定义,调用时加括号
参数传递
位置参数(按顺序)、关键字参数(指定名)、默认参数(提供默认值)
返回值return
 返回结果,无 return 返回 None
作用域
局部变量(函数内)和全局变量(函数外),尽量少用 global
模块化思想
将功能封装成函数,提高复用性和可维护性

下期预告:我们将深入学习函数的高级特性——匿名函数(lambda)、装饰器、以及可变参数 *args 和 `kwargs`**,让你的函数更灵活、更强大!


📌 本期闲谈:

网上很多人说现在项目都ai写了,全都vibe coding了,谁还学习古法编程。我也迷茫了,是不是不应该浪费时间学习,直接all in ai。周末跟朋友聊了聊,他说,ai确实非常方便,想实现一个功能,用ai比自己写快的多,而且ai发展的特别快,刚开始的时候第一款ai软件还是cursor那时他就开始用了,当时的ai能力非常差只能实现简单的代码补全。现在有个想法或具体的功能,ai实现的很快也很好。但ai也有风险,今年六月左右Claude Code爆出隐蔽的检测代码,用日期格式识别中国用户,更早之前ai中转站投毒,生成带恶意脚本的批处理文件。编程学习基础语法肯定没错,你总不能看不懂ai输出的是什么东西就直接运行吧

最新文章

随机文章