Skip to content

函数 ​

学生信息管理系统的功能不断增加时,如果所有代码都写在一个 while 循环中,会出现两个问题:

  1. 主循环越来越长,不容易阅读
  2. 相同逻辑可能重复出现,不方便修改

如何把菜单显示、学生查询、数据保存等功能拆开,并在需要时重复使用?函数可以把一段职责明确的代码单独封装起来:接收数据,完成任务,再把结果交回来。

函数作用与分类 ​

先用四个问题明确函数的作用:

  1. 如何把大程序拆成多个小功能?把每段职责明确的代码封装成函数。
  2. 如何减少重复代码?需要时重复调用同一个函数。
  3. 如何让代码结构更清楚?让主流程只负责组织调用。
  4. 如何方便修改和复用?集中修改函数内部逻辑即可。

例如,学生管理系统可以拆成“显示菜单”“新增学生”“查询学生”“保存数据”等函数。主循环只负责根据用户选择调用对应功能。

函数定义与调用执行流程图

函数分类: 按照来源,函数可以简单分成四类:

类型示例使用方式
内置函数len()、print()可以直接调用
标准库函数random.randint()导入标准库模块后调用
第三方库函数第三方包提供的函数安装并导入第三方包后调用
自定义函数自己使用 def 编写的函数先定义,再调用

这一章重点学习自定义函数。

函数定义与调用 ​

使用 def 定义函数。def 是 define 的缩写,表示“定义”。

函数定义语法结构剖析图

基本结构如下:

python
def 函数名(参数):
    函数体
    return 返回值

一个函数通常包含这些部分:

  1. def:定义函数的关键字
  2. 函数名:调用函数时使用的名字
  3. 参数:函数接收的数据,可以没有
  4. 函数体:函数要执行的代码,必须缩进
  5. return:把结果返回给调用者,可以没有

函数名要遵守标识符规则,通常使用小写字母和下划线。名字尽量表达功能,例如 show_menu、calculate_total。

定义:

先定义一个没有参数的函数,观察定义阶段发生了什么:

python
def show_menu():
    print("1. 新增学生")
    print("2. 显示学生")
    print("0. 退出系统")

运行这段代码时不会显示菜单,因为这里只是定义函数,还没有调用。

调用:

在函数名后加小括号,就是调用函数:

python
def show_menu():
    print("1. 新增学生")
    print("2. 显示学生")
    print("0. 退出系统")


show_menu()

运行结果:

text
1. 新增学生
2. 显示学生
0. 退出系统

代码执行到 show_menu() 时,会进入函数执行函数体。函数体结束后,再回到调用位置继续向下执行。

定义顺序与调用 ​

函数调用执行时,函数名必须已经定义:

python
show_menu()  # NameError


def show_menu():
    print("学生信息管理系统")

Python 从上到下执行代码。运行到第一行时还不知道 show_menu 是什么,因此会出现 NameError。

定义不等于执行

执行 def 只会创建函数,不会运行函数体。只有调用函数时,函数体才会执行。

参数与返回值 ​

没有参数的函数只能完成固定任务。加入参数后,同一个函数就能处理不同数据。

参数接收 ​

例如,函数 f(x) 表示公式:

text
y = 5x + 6

可以这样封装:

python
def f(x):
    y = 5 * x + 6
    return y


print(f(5))
print(f(6))
print(f(7))

运行结果:

text
31
36
41

函数逻辑没有变化,只是每次传入的 x 不同,所以得到了不同结果。

如果公式中的 k 和 b 也需要变化,可以继续增加参数:

python
def calculate_y(x, k, b):
    return k * x + b


print(calculate_y(5, 5, 6))
print(calculate_y(5, 2, 3))

参数的类型、顺序和更多写法,会在下一节集中讲解。

返回值与执行流程 ​

函数完成计算后,可以用 return 把结果交给调用者:

python
def calculate_total(chinese, math, english):
    total = chinese + math + english
    return total


student_total = calculate_total(88, 92, 85)
print(student_total)

运行结果:

text
265

返回值可以保存到变量中,也可以继续参与计算或传给其他函数。

函数参数进入函数并通过 return 返回结果的示意图

输出与返回: print() 只是把内容显示在控制台,return 才会把结果交给函数外部:

python
def print_total(chinese, math):
    print(chinese + math)


result = print_total(88, 92)
print(result)

运行结果:

text
180
None

函数没有执行 return 时,默认返回 None。

提前结束: return 有两个作用:

  1. 返回结果
  2. 立即结束当前函数
python
def get_result():
    return "函数结束"
    print("这行代码不会执行")


print(get_result())

程序执行到 return 后会立刻离开函数,所以后面的 print() 永远不会执行。

多分支返回: 函数里可以编写多个 return,但一次调用只会执行其中一条路径。

下面定义一个函数,判断数字是否为素数:

什么是素数

素数也叫质数,指大于 1,并且只能被 1 和它本身整除的整数。

python
def is_prime(number):
    if number <= 1:
        return False

    for divisor in range(2, number):
        if number % divisor == 0:
            return False

    return True


for number in range(100):
    if is_prime(number):
        print(number, end=" ")

运行结果:

text
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

只要找到一个能整除 number 的数,函数就会立即返回 False。循环全部结束后还没有找到,才返回 True。

容器与多值返回 ​

如果一次计算要交回一组数据,函数可以返回列表、字典等容器;如果要交回多个结果,也可以一次返回多个值。

返回列表:

下面的函数生成一个包含随机数字的列表:

python
import random


def create_random_list(count):
    numbers = []
    for _ in range(count):
        numbers.append(random.randint(0, 9))
    return numbers


result = create_random_list(5)
print(result)

每次运行得到的数字可能不同,但列表长度都是 5。

返回多个值:

需要同时返回多个结果时,可以在 return 后写多个值:

python
def get_score_info(scores):
    highest = max(scores)
    lowest = min(scores)
    total = 0
    for score in scores:
        total += score
    return highest, lowest, total


result = get_score_info([88, 92, 85])
print(result)

highest, lowest, total = result
print(highest, lowest, total)

运行结果:

text
(92, 85, 265)
92 85 265

看上去返回了多个值,实际返回的是一个元组。上一节学习的序列解包,可以直接把元组中的结果交给多个变量。

函数形式 ​

根据“有没有参数”和“有没有返回值”,函数可以分成四种形式。遇到一个新任务时,可以先判断它属于哪一种:

形式示例用途
无参数、无返回值显示固定菜单
无参数、有返回值获取当前时间
有参数、无返回值打印指定学生信息
有参数、有返回值根据三科成绩计算总分

最常用的是“有参数、有返回值”:参数让函数能够处理不同数据,返回值让计算结果可以继续使用。

函数练习 ​

下面用五个小任务练习函数的定义、参数和返回值。

百以内累加:

python
def get_sum():
    total = 0
    for number in range(1, 101):
        total += number
    return total


print(get_sum())

运行结果:

text
5050

range(1, 101) 会生成 1 到 100,不包含结束位置 101。

两数最大值:

参考答案
python
def get_max(number1, number2):
    if number1 > number2:
        return number1
    return number2


print(get_max(1, 3))
print(get_max(11, 3))

范围累加:

参考答案
python
def sum_to_n(n):
    total = 0
    for number in range(1, n + 1):
        total += number
    return total


print(sum_to_n(10))

两数平均值:

参考答案
python
def calculate_average(number1, number2):
    return (number1 + number2) / 2


print(calculate_average(80, 90))

调和数计算:

第 n 阶调和数的计算方式如下:

text
1 + 1/2 + 1/3 + ... + 1/n
参考答案
python
def harmonic(n):
    total = 0
    for number in range(1, n + 1):
        total += 1 / number
    return total


print(harmonic(5))

案例:计算复利 ​

需求:对多组本金、利率和年限计算最终金额,并复用同一套计算逻辑。

功能分析:先把复利公式封装成函数,再用两层循环处理不同方案和年限。

复利公式如下:

text
最终金额 = 本金 × (1 + 年利率) ^ 年限

完成下面的计算:

  1. 本金 10000 元、年利率 2.561%
  2. 本金 10000 元、年利率 6%
  3. 本金 20000 元、年利率 6%
  4. 每组分别计算 5 年、10 年、15 年和 20 年后的金额

先把公式封装成函数:

python
def calculate_balance(principal, interest, years):
    balance = principal * (1 + interest) ** years
    return balance

Python 中使用 ** 计算乘方。利率需要转换成小数,例如 6% 写成 0.06。

复利函数处理多组方案的复用流程图

接下来准备三组方案和四个年限,再重复调用函数:

python
def calculate_balance(principal, interest, years):
    balance = principal * (1 + interest) ** years
    return balance


plans = [
    (10000, 0.02561),
    (10000, 0.06),
    (20000, 0.06),
]
year_options = [5, 10, 15, 20]

for principal, interest in plans:
    for years in year_options:
        balance = calculate_balance(principal, interest, years)
        print(
            f"本金:{principal} 元,"
            f"年利率:{interest:.3%},"
            f"年限:{years} 年,"
            f"最终金额:{balance:.2f} 元"
        )

函数只负责计算复利。外层循环负责取出不同方案,内层循环负责处理不同年限。以后公式变化时,只需要修改函数内部。

小结 ​

本节围绕四个问题掌握函数基础:

  1. 如何封装并调用一段功能?使用 def 定义函数,通过函数名加小括号调用。
  2. 如何让同一个函数处理不同数据?通过参数接收数据。
  3. 如何把结果交给函数外部?使用 return,它还会立即结束当前函数。
  4. 如何减少重复代码?把程序拆成职责明确、可以复用的函数。

练习 ​

  1. 编写函数,接收圆的半径并返回面积
  2. 编写函数,接收两个数并返回较小值
  3. 编写函数,接收 n 并返回 1 到 n 之间所有偶数的和
  4. 把学生管理系统的菜单输出封装成 show_menu() 函数