Skip to content

第 7 章 函数

学习目标

  • 会用 def 定义函数、用 return 返回结果
  • 掌握默认参数、关键字参数、*args**kwargs
  • 理解局部变量与全局变量的作用域
  • 认识 lambda 与递归(选学)

7.1 定义与调用

函数是一段有名字、可重复调用的代码。用 def 定义:

python
def greet(name):
    return f"你好,{name}!"

print(greet("小明"))

输出:

你好,小明!

语法要点:

  1. def 后面跟函数名、括号和冒号。
  2. 括号里是参数(函数需要的输入),name 在这里是形参。
  3. return 把计算结果返回给调用者。
  4. 调用时在函数名后加括号并传入实参:greet("小明")

return可省略的。没有 return(或只有 return 不带值)的函数,返回值是 None:

python
def nothing():
    pass

print(nothing())

输出:

None

None 是 Python 表示「什么都没有」的特殊值。

7.2 参数

默认参数:定义时给参数指定默认值,调用时可以不传:

python
def power(base, exp=2):
    return base ** exp

print(power(3))      # exp 用默认值 2
print(power(2, 10))  # 显式传入 exp

输出:

9
1024

关键字参数:调用时用 参数名=值 的形式,可以不按顺序传:

python
print(power(exp=3, base=2))

输出:

8

*args:收集任意数量的位置参数,在函数内是一个元组:

python
def add_all(*nums):
    return sum(nums)

print(add_all(1, 2, 3))
print(add_all(1, 2, 3, 4, 5))

输出:

6
15

**kwargs:收集任意数量的关键字参数,在函数内是一个字典:

python
def show(**kwargs):
    return kwargs

print(show(name="小明", age=18))

输出:

{'name': '小明', 'age': 18}

*args**kwargs 是约定俗成的名字,常用于「不知道调用者会传多少参数」的场景,例如日志、配置收集。

返回值可以有多个——实际返回的是一个元组,调用时用多个变量接收即可:

python
def minmax(lst):
    return min(lst), max(lst)

lo, hi = minmax([3, 1, 2])
print(lo, hi)

输出:

1 3

7.3 作用域

作用域决定一个名字在哪些地方可以被访问。函数内部定义的变量叫局部变量,只存在于函数内部;函数外定义的叫全局变量

python
def f():
    x = 10       # 局部变量,函数外不可见

print(x)         # 报错:NameError: name 'x' is not defined

函数内可以读取全局变量,但想修改它必须用 global 声明:

python
count = 0

def add_one():
    global count
    count += 1

add_one()
add_one()
print(count)

输出:

2

不加 global 时,count += 1 会被当成「创建一个新的局部变量 count」,函数外的 count 不会被修改。规则简单记:默认情况下,函数内只能读全局变量,不能改。

7.4 lambda(选学)

lambda 用来写「一句话的函数」,即只有一个表达式、自动返回结果的小函数:

python
double = lambda x: x * 2
print(double(4))

输出:

8

等价于:

python
def double(x):
    return x * 2

lambda 最常见的用途是作为参数传给其他函数。例如 sortedkey 参数指定排序依据:

python
words = ["banana", "apple", "cherry"]
print(sorted(words, key=len))

输出:

['apple', 'banana', 'cherry']

按长度排序,而不是默认的字典序。等价的具名函数写法是 def by_len(w): return len(w);lambda 只是更短。

7.5 递归(选学)

递归指函数调用自身。递归必须有终止条件,否则会无限调用直至报错。经典例子:阶乘 n! = n × (n-1)!

python
def fact(n):
    if n <= 1:
        return 1
    return n * fact(n - 1)

print(fact(5))

输出:

120

计算过程:fact(5)5 * fact(4)5 * 4 * fact(3) → … → 5 × 4 × 3 × 2 × 1 = 120if n <= 1: return 1 是终止条件。递归能简洁地表达分治类问题,但注意:递归层数过深会报 RecursionError

动手实践

任务:把前面章节的程序改造成函数。 第 2 章的温度换算、第 6 章的成绩统计,各写成一个函数。

python
def celsius_to_fahrenheit(c):
    return c * 9 / 5 + 32

def score_report(text):
    scores = [int(x) for x in text.split(",")]
    return {
        "平均分": sum(scores) / len(scores),
        "最高分": max(scores),
        "最低分": min(scores),
        "及格人数": len([s for s in scores if s >= 60]),
    }

print(celsius_to_fahrenheit(25))
print(score_report("85,92,78,90,66"))

输出:

77.0
{'平均分': 82.2, '最高分': 92, '最低分': 66, '及格人数': 5}

函数的好处:一次写好,到处调用;想改逻辑只需改一处。

常见错误

错误写法报错信息原因
def f(a, b): ... 然后 f(1)TypeError: f() missing 1 required positional argument: 'b'实参个数少于形参
f(1, 2, 3)(形参只有 2 个)TypeError: f() takes 2 positional arguments but 3 were given实参个数多于形参
函数内 x = 10,函数外 print(x)NameError: name 'x' is not definedx 是局部变量,外面不可见
函数内直接 count += 1 修改全局变量不报错但全局变量没变修改全局变量需要 global 声明
忘记写 return,结果总是 None不报错但结果不对检查是否漏了 return

章末练习

基础

  1. 写函数 is_even(n),返回 n 是否为偶数。
  2. 写函数 circle_area(r),返回半径为 r 的圆面积(3.14 * r ** 2),调用时输出半径 5 的结果。
  3. 写函数 repeat(text, times=2),返回 text 重复 times 次的字符串;分别用 repeat("ha")repeat("ha", 3) 调用并输出。

提高

  1. 写函数 average(*nums),返回所有参数的平均值,并用 average(1, 2, 3, 4) 验证(结果是 2.5)。
  2. 写函数 count_chars(text),返回一个字典,记录 text 中每个字符出现的次数,如 count_chars("hello") 返回 {"h": 1, "e": 1, "l": 2, "o": 1}。提示:遍历字符串,字典计数。

挑战

  1. 用递归写函数 fib(n),返回斐波那契数列第 n 项(第 1、2 项为 1,之后每项是前两项之和),验证 fib(10) 等于 55。
  2. 写出 sorted(["bb", "a", "ccc"], key=len) 的结果,再写一个等价效果的 lambda 表达式,运行验证。

章末自测

每题选择一个最佳答案。本书不附答案:完成后交由老师或 AI 老师批改讲解。

  1. 定义函数的关键字是?
    • A. func
    • B. def
    • C. function
    • D. fn
  2. 函数没有 return 时,返回值是?
    • A. 0
    • B. None
    • C. 报错
    • D. False
  3. def power(base, exp=2): return base ** exp ,power(3) 的结果是?
    • A. 6
    • B. 9
    • C. 8
    • D. 报错
  4. 调用 f(exp=3, base=2) 使用的是?
    • A. 位置参数
    • B. 关键字参数
    • C. 默认参数
    • D. 全局参数
  5. *args 在函数内是?
    • A. 列表
    • B. 元组
    • C. 字典
    • D. 字符串
  6. 函数内定义的变量是?
    • A. 全局变量
    • B. 局部变量
    • C. 常量
    • D. 内置变量
  7. 函数内要修改全局变量,需要?
    • A. 直接用即可
    • B. global 声明
    • C. nonlocal 声明
    • D. 重新定义
  8. lambda x: x * 2 等价于?
    • A. def f(x): return x * 2
    • B. def f(x): x * 2
    • C. return x * 2
    • D. 一个列表
  9. 递归函数最重要的是要有?
    • A. for 循环
    • B. 终止条件
    • C. 全局变量
    • D. lambda
  10. fact(5)(阶乘函数)的结果是? A. 15 B. 120 C. 25 D. 720