0%

已完成 0/14 关

教学模式

你可以随时调整。

此设置调整教师的教学方式,无需重新生成课程。

第 5 关 含代码 约 13 分钟

函数定义与参数机制

为什么要定义函数(Function)?

当程序规模变大时,如果一段重复的计算逻辑在代码各处复制粘贴,一旦需要修改就会引发灾难性的维护成本。**函数(function)**是编程中最重要的抽象工具:它将一段具有明确输入与输出的独立逻辑封装在一起,起一个名字,供随时调用。

1. 使用 def 关键字定义函数

在 Python 中,使用关键字 def(define 的缩写)来创建函数:

def fib(n):
    """Print a Fibonacci series less than n."""
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a + b
    print()

# 调用我们定义的函数:
fib(2000)

输出:

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

核心解构:

  1. 函数签名:def fib(n):,以 def 开头,后跟函数名和圆括号内的形参列表(parameters),行末紧跟冒号;
  2. 函数体缩进:冒号下方属于函数内部的所有语句必须统一向右缩进 4 个空格;
  3. 文档字符串(docstring):函数内部的第一条语句如果是一个多行字符串 """...""",它会被自动识别为文档字符串。它是对该函数功能、参数与返回值的权威说明,可以通过 help(fib) 或开发工具直接查阅,编写清晰的 docstring 是专业开发者的标志性习惯;
  4. 函数也是第一类对象:函数名 fib 实际上指向了一个可调用的函数对象。你可以把它赋值给其他变量(如 f = fib),然后使用 f(100) 来调用它。

2. 关键心智模型:print() 与 return 的根本差异

初学者经常混淆“屏幕打印”与“函数返回”:

  • print():纯粹是向屏幕输出字符给人眼阅读。外层的调用代码根本“拿不到”这个值;
  • return:是把计算生成的数据“交还”给调用方。外部可以用变量承接这个结果,并进行后续存储或二次计算;
  • 没有 return 的函数:如果函数执行完毕没有遇到任何 return 语句,Python 会默认默默返回内置特殊对象 None(表示“空”)。

官方教程通过对比 fib(n) 与 fib2(n) 深刻阐明了这一点:

def fib2(n):
    """Return a list containing the Fibonacci series up to n."""
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a + b
    return result

# 调用它并用变量接收返回值:
f100 = fib2(100)
print(f100)

输出:

[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

此时,f100 是一个真正的列表对象,你可以对它求 len(f100) 或进行切片筛选。

3. 函数参数详解

Python 拥有极其灵活多样的传参机制:

默认值参数(Default Argument Values)

可以为形参指定默认值,调用时如果省略该参数,则自动采用默认值:

def ask_ok(prompt, retries=4, reminder='Please try again!'):
    while True:
        reply = input(prompt)
        if reply in {'y', 'ye', 'yes'}:
            return True
        if reply in {'n', 'no', 'nop', 'nope'}:
            return False
        retries = retries - 1
        if retries < 0:
            raise ValueError('invalid user response')
        print(reminder)

重要陷阱:可变默认参数只在函数定义时求值一次! 如果默认值是一个可变对象(如列表 L=[]),后续多次调用会共享并累积同一个列表:

def f(a, L=[]):
    L.append(a)
    return L
print(f(1))  # [1]
print(f(2))  # [1, 2] -- 发生了累积!

官方推荐的安全写法:默认值设为 None,并在函数体内动态创建新列表:

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

关键字参数(Keyword Arguments)

调用函数时,可以通过 形参名=值 的方式明确指定实参,无需死记位置顺序:

def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print("-- This parrot wouldn't", action, end=' ')
    print("if you put", voltage, "volts through it.")

# 合法调用方式:
parrot(1000)                                  # 1 个位置参数
parrot(voltage=1000)                          # 1 个关键字参数
parrot(voltage=1000000, action='VOOOOOM')     # 2 个关键字参数
parrot('a thousand', state='pushing up daisies') # 位置参数必须在关键字参数之前

任意实参列表:*args 与 **kwargs

  • *args:将多余传入的位置参数打包为一个元组(tuple);
  • **kwargs:将多余传入的关键字参数打包为一个字典(dict):
def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    for arg in arguments:
        print(arg)
    for kw in keywords:
        print(kw, ":", keywords[kw])

解包实参列表(Unpacking Argument Lists)

如果你手头已经有一个列表或元组,想把它解开当成独立的位置参数传给函数,可以在前面加一个星号 *;如果是一个字典,可以使用两个星号 ** 解包为关键字参数:

args = [3, 6]
list(range(*args))  # 等价于 range(3, 6)

Lambda 表达式

可以使用 lambda 关键字创建小巧的单行匿名函数,常用于排序键值:

pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
pairs.sort(key=lambda pair: pair[1])

掌握了函数及其传参体系,我们已经能够将代码组织得井井有条。下一关,我们将深入 Python 丰富的数据结构,掌握堆栈、队列、推导式与字典的高效用法!

下一站:深入列表与列表推导式 →
© 2026 Python 官方教程