Python 学习笔记(第六期)——函数:定义、参数传递与作用域

Python 学习笔记(第六期)------函数:定义、参数传递与作用域

更多Python知识:Python基础入门

我的主页:AOwhisky,这里有更多运维系统性知识整理和其他有趣内容,欢迎与我一起探讨学习~

📖 引言:代码的"积木式"组装

在前五期中,我们掌握了变量、运算符、流程控制和组合数据类型,能够编写出功能完整的程序。但随着程序复杂度提高,一个不可避免的问题出现了------代码重复

假设你需要在一个程序的不同位置打印三次"欢迎使用本系统"------你会选择把同一段代码复制粘贴三次,还是把这段代码封装起来、需要时直接调用?显然是后者。这不仅减少了代码量,更重要的是------如果将来要修改欢迎语的内容,你只需要改一个地方。

这就是函数的价值。

函数就像一块块"乐高积木",每一块都封装了特定的功能。当你需要完成某个任务时,只需"拼搭"对应的积木即可,无需关心积木内部的构造。本期将系统地学习 Python 中函数的定义与调用、参数传递、返回值、变量作用域,以及递归和匿名函数等高级用法。
--- Compiled and Authored by Whisky --- July 14 th, 2026

📑 本期目录

  1. 函数概述(为什么需要函数)
  2. 函数的定义与调用
  3. 函数参数传递(位置参数、关键字参数、默认参数)
  4. 参数的打包与解包(*args**kwargs
  5. 混合参数传递
  6. 函数的返回值
  7. 变量作用域(局部变量、全局变量、LEGB 原则)
  8. 特殊形式的函数(递归函数、匿名函数 lambda)
  9. 综合实战演练(三个完整案例)
  10. 总结与知识点一览表

正文

一、函数概述

1.1 为什么需要函数?

在实际开发中,如果若干段代码的执行逻辑完全相同,将这些代码抽取成函数可以带来多重好处:

好处 说明
减少冗余 相同的逻辑只需编写一次,多处调用
提高可维护性 修改功能时只需改函数内部,调用处无需改动
模块化 将复杂程序拆解为多个小功能,每个函数专注一件事
代码复用 写好的函数可以在不同项目中重复使用
便于测试 每个函数可以独立测试,定位 bug 更容易
1.2 使用函数前 vs 使用函数后

未使用函数(重复代码)

python 复制代码
# 打印边长为2的正方形
for i in range(2):
    for j in range(2):
        print("*", end="")
    print()

# 打印边长为3的正方形
for i in range(3):
    for j in range(3):
        print("*", end="")
    print()

# 打印边长为4的正方形
for i in range(4):
    for j in range(4):
        print("*", end="")
    print()

使用函数后(封装复用)

python 复制代码
def print_square(length):
    """打印指定边长的正方形"""
    for i in range(length):
        for j in range(length):
            print("*", end="")
        print()

# 调用函数,一行搞定
print_square(2)
print_square(3)
print_square(4)

💡 白话理解:函数就像一个"自动化工具"。你只需要告诉它"做什么"(输入参数),它就会帮你完成"怎么做"的具体细节,最后把结果给你。你不必关心工具内部如何运转,只需要知道如何使用它。

二、函数的定义与调用

2.1 定义函数

Python 使用 def 关键字定义函数,语法格式如下:

python 复制代码
def 函数名([参数列表]):
    """文档字符串(可选)"""
    函数体
    [return 返回值]

组成部分说明

组成部分 说明 是否必须
def 定义函数的关键字 ✅ 必须
函数名 函数的唯一标识,遵循标识符命名规则 ✅ 必须
() 包裹参数列表 ✅ 必须
参数列表 接收外部传入的数据 ❌ 可选
: 标记函数体开始 ✅ 必须
文档字符串 说明函数的功能,用三引号包裹 ❌ 建议
函数体 实现具体功能的代码 ✅ 必须
return 返回结果给调用方 ❌ 可选
python 复制代码
def add():
    """无参数函数:计算 11 + 22"""
    result = 11 + 22
    print(result)

def add_modify(a, b):
    """有参数函数:计算两个数的和"""
    result = a + b
    print(result)
2.2 调用函数

函数定义后不会自动执行,只有在被调用时才会执行。

python 复制代码
# 调用无参函数
add()              # 输出:33

# 调用有参函数
add_modify(10, 20) # 输出:30

函数调用执行流程

text 复制代码
程序执行到函数调用处
        ↓
暂停当前代码执行
        ↓
将实参传递给形参
        ↓
进入函数体执行
        ↓
执行完毕(或遇到 return)
        ↓
回到暂停处继续执行
2.3 嵌套调用与嵌套定义

嵌套调用:函数内部调用另一个函数。

python 复制代码
def add():
    result = 11 + 22
    print(result)

def add_modify(a, b):
    result = a + b
    add()                # 嵌套调用 add()
    print(result)

add_modify(10, 20)
# 输出:
# 33(来自 add())
# 30(来自 add_modify())

嵌套定义:在函数内部定义另一个函数。内层函数只能在外层函数内部被调用。

python 复制代码
def outer(a, b):
    result = a + b

    def inner():         # 嵌套定义
        print("这是内层函数")

    inner()              # 外层函数内调用内层函数
    print(result)

outer(10, 20)
# 输出:
# 这是内层函数
# 30

# inner()  # ❌ 外部无法直接调用内层函数

⚠️ 注意:内层函数的作用域仅限于外层函数内部,外部代码无法直接调用。

三、函数参数传递

我们将定义函数时设置的参数称为形式参数(形参) ,将调用函数时传入的参数称为实际参数(实参)。参数传递就是将实参传递给形参的过程。

3.1 位置参数传递

实参按照位置顺序依次传递给形参------第一个实参传给第一个形参,第二个传给第二个,以此类推。

python 复制代码
def get_max(a, b):
    if a > b:
        print(f"最大值:{a}")
    else:
        print(f"最大值:{b}")

get_max(5, 8)   # 5 传给 a,8 传给 b → 最大值:8
get_max(8, 5)   # 8 传给 a,5 传给 b → 最大值:8

⚠️ 注意:位置参数的顺序非常重要。调换顺序可能导致逻辑错误。

3.2 关键字参数传递

通过 形参名=实参值 的格式显式指定实参与形参的对应关系,顺序无关紧要。

python 复制代码
def connect(ip, port):
    print(f"连接设备 {ip}:{port}")

# 以下三种调用方式等价
connect("127.0.0.1", 8080)                    # 位置参数
connect(ip="127.0.0.1", port=8080)            # 关键字参数
connect(port=8080, ip="127.0.0.1")            # 关键字参数(顺序可调换)
3.3 位置参数与关键字参数的混合

Python 3.8+ 引入了仅限位置参数/)和仅限关键字参数*)的语法:

python 复制代码
def demo(a, b, /, c, *, d, e):
    print(a, b, c, d, e)

# a 和 b 只能按位置传递
# c 可以按位置或关键字传递
# d 和 e 只能按关键字传递

demo(1, 2, 3, d=4, e=5)    # ✅ 正确
demo(1, 2, c=3, d=4, e=5)  # ✅ 正确
# demo(1, 2, 3, 4, 5)      # ❌ d 和 e 必须用关键字
3.4 默认参数

函数定义时可以为形参指定默认值。调用时若未传入对应实参,则使用默认值。

python 复制代码
def connect(ip, port=8080):
    print(f"连接设备 {ip}:{port}")

connect("127.0.0.1")           # 使用默认 port=8080 → 连接设备 127.0.0.1:8080
connect("127.0.0.1", 3306)     # 覆盖默认值 → 连接设备 127.0.0.1:3306
connect(ip="127.0.0.1", port=3306)

⚠️ 注意 :带有默认值的参数必须位于普通参数之后

python 复制代码
# ❌ 错误:默认参数不能在普通参数前面
def wrong(a=1, b):   # SyntaxError
    pass

# ✅ 正确
def correct(b, a=1):
    pass

四、参数的打包与解包

4.1 打包------接收不定数量的参数

当函数无法预知会传入多少个参数时,可以使用 *args**kwargs 进行"打包"。

符号 用途 打包成的类型 命名建议
* 接收多个位置参数 元组(tuple) *args
** 接收多个关键字参数 字典(dict) **kwargs
python 复制代码
# *args:打包位置参数为元组
def test_args(*args):
    print(args)

test_args(11, 22, 33, 44, 55)   # (11, 22, 33, 44, 55)

# **kwargs:打包关键字参数为字典
def test_kwargs(**kwargs):
    print(kwargs)

test_kwargs(a=1, b=2, c=3, d=4)  # {'a': 1, 'b': 2, 'c': 3, 'd': 4}

💡 命名约定 :虽然 *** 后面的名称可以任意,但社区约定使用 *args**kwargs,这是 Python 程序员普遍识别的写法。如果没有接收到任何参数,args 为空元组 ()kwargs 为空字典 {}

4.2 解包------将序列/字典拆分为实参

打包的反向操作------将序列或字典"拆开",作为实参传递给函数。

python 复制代码
def test(A, B, C, D):
    print(A, B, C, D)

# 元组解包:每个元素对应一个位置参数
numbers = (10, 20, 30, 40)
test(*numbers)   # 10 20 30 40

# 字典解包:键名必须与形参名一致
dic = {'A': 11, 'C': 22, 'B': 33, 'D': 44}
test(**dic)      # 11 33 22 44

⚠️ 注意 :字典解包时,字典的键名必须与函数的形参名完全一致,否则会报错。

五、混合参数传递

在实际开发中,多种参数传递方式可以混合使用,但必须遵循以下顺序规则。

定义函数时的顺序

text 复制代码
普通参数 → 默认参数 → *args → **kwargs
python 复制代码
def mixed(a, b, c=33, *args, **kwargs):
    print(f"a={a}, b={b}, c={c}, args={args}, kwargs={kwargs}")

mixed(1, 2)                       # a=1, b=2, c=33, args=(), kwargs={}
mixed(1, 2, 3)                    # a=1, b=2, c=3, args=(), kwargs={}
mixed(1, 2, 3, 4)                 # a=1, b=2, c=3, args=(4,), kwargs={}
mixed(1, 2, 3, 4, e=5)            # a=1, b=2, c=3, args=(4,), kwargs={'e': 5}
mixed(1, 2, e=5)                  # a=1, b=2, c=33, args=(), kwargs={'e': 5}

调用函数时的顺序

text 复制代码
位置参数 → 关键字参数 → *args 解包 → **kwargs 解包

💡 记忆口诀:定义时,普通在前、默认中间、打包在最后;调用时,位置在前、关键字在后。

六、函数的返回值

函数使用 return 语句将处理结果返回给调用方,同时函数执行结束。

6.1 返回单个值
python 复制代码
def add(a, b):
    return a + b

result = add(10, 20)
print(result)   # 30
6.2 返回多个值(封装为元组)
python 复制代码
def move(x, y, step):
    next_x = x + step
    next_y = y - step
    return next_x, next_y   # 返回元组 (next_x, next_y)

result = move(10, 20, 5)
print(result)      # (15, 15)
print(type(result)) # <class 'tuple'>

# 元组解包接收
x, y = move(10, 20, 5)
print(x, y)        # 15 15
6.3 没有 return 时返回 None
python 复制代码
def no_return():
    print("没有 return 语句")

result = no_return()
print(result)   # None

七、变量作用域

变量并非在程序的任意位置都可以被访问,其可访问的范围称为作用域

7.1 局部变量 vs 全局变量
类型 定义位置 作用范围 生命周期
局部变量 函数内部 仅限函数内部 函数执行结束即释放
全局变量 函数外部 整个程序 程序运行期间一直存在
python 复制代码
# 全局变量
global_var = 100

def test():
    # 局部变量
    local_var = 10
    print(f"函数内访问全局变量:{global_var}")   # ✅ 可以读取
    print(f"局部变量:{local_var}")              # ✅ 可以访问

test()
print(global_var)   # ✅ 可以访问
# print(local_var)  # ❌ NameError:函数外部无法访问局部变量
7.2 全局变量的修改------global 关键字

在函数内部读取 全局变量是允许的,但直接修改会报错:

python 复制代码
num = 10

def test():
    num += 1   # ❌ UnboundLocalError
    print(num)

test()

报错原因 :函数内部的 num += 1 被 Python 解释器视为声明了一个新的局部变量 num,但在赋值之前就被引用了,所以报错。

解决方案 :使用 global 关键字声明。

python 复制代码
num = 10

def test():
    global num   # 声明 num 为全局变量
    num += 1
    print(num)

test()           # 11
print(num)       # 11(全局变量被修改了)
7.3 嵌套作用域的修改------nonlocal 关键字

在嵌套函数中,使用 nonlocal 可以修改外层函数的局部变量。

python 复制代码
def outer():
    num = 10

    def inner():
        nonlocal num   # 声明 num 来自外层函数
        num += 1
        print(f"内层:{num}")

    inner()            # 内层:11
    print(f"外层:{num}")  # 外层:11

outer()
7.4 LEGB 原则

Python 在查找变量时遵循 LEGB 顺序:

缩写 全称 说明
L Local 局部作用域(函数内部)
E Enclosing 嵌套作用域(外层函数的局部作用域)
G Global 全局作用域(模块级别)
B Built-in 内置作用域(Python 内置的标识符)
python 复制代码
import math   # Built-in

g_num = 10    # Global

def outer():   # Enclosing
    e_num = 20

    def inner():  # Local
        l_num = 30
        print(l_num)       # Local
        print(e_num)       # Enclosing
        print(g_num)       # Global
        print(math.pi)     # Built-in

    inner()

outer()

💡 白话理解:LEGB 可以理解为"就近原则"------Python 从最近的区域开始找变量,找不到就往外层找,直到内置作用域。就像你在家里找钥匙------先看口袋(Local),再看客厅(Enclosing),然后看整个屋子(Global),最后才去物业(Built-in)问。

八、特殊形式的函数

8.1 递归函数

递归函数是指在函数内部调用自身的函数。递归需要满足两个条件:

条件 说明 示例(阶乘)
边界条件 递归终止的条件,不能再继续分解 n == 1 时返回 1
递归公式 将原问题分解为更小的子问题 n! = n * (n-1)!

递归执行的两个阶段

text

复制代码
递推:将问题不断分解为更小的子问题,直到达到边界条件
回溯:从边界条件开始,逐层返回计算结果

案例:阶乘 n!

python 复制代码
def factorial(n):
    if n == 1:          # 边界条件
        return 1
    else:               # 递归公式
        return n * factorial(n - 1)

result = factorial(5)
print(f"5! = {result}")   # 120

执行过程追踪

text 复制代码
factorial(5)
    return 5 * factorial(4)
                return 4 * factorial(3)
                            return 3 * factorial(2)
                                        return 2 * factorial(1)
                                                    return 1
                                        return 2 * 1 = 2
                            return 3 * 2 = 6
                return 4 * 6 = 24
    return 5 * 24 = 120

案例:斐波那契数列(兔子数列)

斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, ...,从第3项开始,每一项等于前两项之和。

python 复制代码
def fibonacci(n):
    if n == 1 or n == 2:    # 边界条件
        return 1
    else:                   # 递归公式
        return fibonacci(n - 1) + fibonacci(n - 2)

# 输出前10项
for i in range(1, 11):
    print(fibonacci(i), end=" ")   # 1 1 2 3 5 8 13 21 34 55

⚠️ 性能提示:递归虽然代码简洁,但存在效率问题(如斐波那契数列有大量重复计算)。对于大规模计算,迭代(循环)通常更高效。

8.2 匿名函数(lambda)

lambda 函数是一种没有名称的函数,用于定义简单的、单行表达式的功能。

python 复制代码
lambda 参数列表: 表达式

与普通函数的对比

对比维度 普通函数(def) 匿名函数(lambda)
名称 有名称 无名称
函数体 多条语句 只能有一个表达式
返回值 可用 return 显式返回 表达式的结果自动作为返回值
复杂度 可实现复杂功能 仅限简单功能
python 复制代码
# 定义匿名函数并赋值给变量
square = lambda x: x ** 2
print(square(10))   # 100

# 多个参数
add = lambda x, y: x + y
print(add(10, 20))  # 30

# 直接在调用处使用
result = (lambda x, y: x * y)(5, 6)
print(result)       # 30

lambda 的典型应用场景 :作为 sorted()map()filter() 等函数的参数。

python 复制代码
# 按字典的某个字段排序
students = [
    {'name': '张三', 'score': 85},
    {'name': '李四', 'score': 92},
    {'name': '王五', 'score': 78}
]
# 按成绩升序排序
sorted_students = sorted(students, key=lambda x: x['score'])
print(sorted_students)
# [{'name': '王五', 'score': 78}, {'name': '张三', 'score': 85}, {'name': '李四', 'score': 92}]

九、综合实战演练

实战一:角谷猜想(冰雹猜想)

需求描述:角谷猜想是指:对于任意一个正整数 n,如果 n 是偶数,则变为 n/2;如果 n 是奇数,则变为 3n+1。重复此过程,最终会得到 1。本程序计算经过多少步可变为 1。

涉及知识点:函数定义、递归函数、条件判断

python 复制代码
def collatz_steps(n, steps=0):
    """
    计算角谷猜想的步数
    参数:
        n: 当前数字
        steps: 已走过的步数
    返回:
        最终步数
    """
    if n == 1:
        return steps
    elif n % 2 == 0:
        return collatz_steps(n // 2, steps + 1)
    else:
        return collatz_steps(3 * n + 1, steps + 1)

# 测试
num = int(input("请输入一个正整数:"))
step_count = collatz_steps(num)
print(f"{num} 经过 {step_count} 步变为 1")

运行示例

text 复制代码
请输入一个正整数:12
12 经过 9 步变为 1

执行过程:12 → 6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1

实战二:饮料自动售货机

需求描述:实现一个饮料自动售货机程序,具备以下功能:

  1. 显示所有饮品的名称、价格和库存
  2. 用户选择饮品和购买数量
  3. 计算总价并完成购买(更新库存)

涉及知识点:函数定义、字典操作、参数传递、返回值

python 复制代码
# 饮料自动售货机

# 初始化库存(字典)
inventory = {
    "可乐": {"price": 3.5, "stock": 10},
    "雪碧": {"price": 3.0, "stock": 8},
    "矿泉水": {"price": 2.0, "stock": 15},
    "咖啡": {"price": 5.5, "stock": 5}
}

def show_products():
    """显示所有饮品信息"""
    print("\n" + "=" * 40)
    print("      🥤 饮品列表")
    print("=" * 40)
    print("序号\t名称\t\t价格\t库存")
    print("-" * 40)
    idx = 1
    for name, info in inventory.items():
        print(f"{idx}\t{name}\t\t¥{info['price']:.1f}\t{info['stock']} 瓶")
        idx += 1
    print("=" * 40)

def buy_product(name, quantity):
    """
    购买饮品
    参数:
        name: 饮品名称
        quantity: 购买数量
    返回:
        (success, message, total_price)
    """
    if name not in inventory:
        return False, "该饮品不存在!", 0

    info = inventory[name]
    if info["stock"] < quantity:
        return False, f"库存不足!当前库存:{info['stock']} 瓶", 0

    total = info["price"] * quantity
    info["stock"] -= quantity
    return True, f"购买成功!共需支付 ¥{total:.2f}", total

def main():
    """主程序"""
    print("=" * 40)
    print("      欢迎使用自动售货机")
    print("=" * 40)

    while True:
        show_products()

        choice = input("请输入序号选择饮品(输入 0 退出):")
        if choice == "0":
            print("感谢使用,再见!")
            break

        # 根据序号获取饮品名称
        names = list(inventory.keys())
        try:
            idx = int(choice) - 1
            if idx < 0 or idx >= len(names):
                print("❌ 无效序号!")
                continue
            name = names[idx]
        except ValueError:
            print("❌ 请输入有效数字!")
            continue

        try:
            quantity = int(input(f"请输入购买数量({name}):"))
            if quantity <= 0:
                print("❌ 数量必须大于 0!")
                continue
        except ValueError:
            print("❌ 请输入有效数字!")
            continue

        success, message, total = buy_product(name, quantity)
        print(f"✅ {message}")

main()

运行示例

text 复制代码
========================================
      欢迎使用自动售货机
========================================

========================================
      🥤 饮品列表
========================================
序号    名称        价格    库存
----------------------------------------
1       可乐        ¥3.5   10 瓶
2       雪碧        ¥3.0   8 瓶
3       矿泉水      ¥2.0   15 瓶
4       咖啡        ¥5.5   5 瓶
========================================
请输入序号选择饮品(输入 0 退出):1
请输入购买数量(可乐):3
✅ 购买成功!共需支付 ¥10.50
实战三:归并排序(递归经典应用)

需求描述:归并排序是一种基于"分治策略"的排序算法------将序列不断二分,直到每个子序列长度为 1,然后两两合并成有序序列。

涉及知识点:递归函数、列表操作、函数嵌套

python 复制代码
# 归并排序

def merge_sort(arr):
    """归并排序主函数"""
    if len(arr) <= 1:
        return arr

    # 1. 分解:将数组分为两半
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])

    # 2. 合并:将两个有序数组合并为一个
    return merge(left, right)

def merge(left, right):
    """合并两个有序数组"""
    result = []
    i = j = 0

    # 比较两个数组的元素,依次放入结果
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1

    # 剩余元素直接追加
    result.extend(left[i:])
    result.extend(right[j:])

    return result

# 测试
data = [8, 4, 5, 7, 1, 3, 6, 2]
print(f"原始数据:{data}")
sorted_data = merge_sort(data)
print(f"排序结果:{sorted_data}")

运行结果

text 复制代码
原始数据:[8, 4, 5, 7, 1, 3, 6, 2]
排序结果:[1, 2, 3, 4, 5, 6, 7, 8]

执行流程

text 复制代码
                    [8, 4, 5, 7, 1, 3, 6, 2]
                         /              \
                  [8, 4, 5, 7]      [1, 3, 6, 2]
                   /      \          /      \
              [8, 4]   [5, 7]   [1, 3]   [6, 2]
              /   \    /   \    /   \    /   \
            [8]  [4] [5]  [7] [1]  [3] [6]  [2]
              \   /    \   /    \   /    \   /
              [4, 8]   [5, 7]   [1, 3]   [2, 6]
                   \      /          \      /
                  [4, 5, 7, 8]   [1, 2, 3, 6]
                         \              /
                    [1, 2, 3, 4, 5, 6, 7, 8]

十、补充知识:函数式编程思想

函数式编程是一种编程范式,强调使用纯函数 (无副作用、相同输入永远得到相同输出)和不可变数据。虽然 Python 不是纯函数式语言,但吸收了很多函数式编程的特性:

特性 Python 支持 说明
高阶函数 map()filter()reduce() 函数可以作为参数传递或返回值
匿名函数 lambda 快速定义简单的单行函数
列表推导式 [x for x in ...] 替代 map()filter() 的常见用法
不可变数据 ✅ 元组、字符串、数字 虽然 Python 有可变类型,但也支持不可变类型
python 复制代码
# 使用 map + lambda 对列表每个元素平方
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared)   # [1, 4, 9, 16, 25]

# 使用 filter + lambda 过滤偶数
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens)     # [2, 4]

# 使用列表推导式(更 Pythonic)
squared = [x ** 2 for x in numbers]
print(squared)   # [1, 4, 9, 16, 25]

📝 总结与知识点一览表

核心知识点汇总

类别 知识点 关键语法
函数定义 def + 函数名 + 参数 + 函数体 def func():
参数传递 位置参数、关键字参数、默认参数 def func(a, b=1):
参数打包 接收不定数量参数 *args**kwargs
参数解包 拆分序列/字典作为实参 *list**dict
返回值 返回结果并结束函数 return value
局部变量 函数内部定义 x = 10(函数内)
全局变量 函数外部定义 x = 10(函数外)
全局修改 函数内修改全局变量 global x
嵌套修改 内层函数修改外层变量 nonlocal x
递归函数 函数调用自身 边界条件 + 递归公式
匿名函数 单行表达式函数 lambda x: x*2
高阶函数 函数作为参数/返回值 map()filter()

常用语法速查

需求 代码示例
定义无参函数 def hello(): print("Hello")
定义有参函数 def add(a, b): return a + b
默认参数 def connect(ip, port=8080):
不定长参数 def sum_all(*args): return sum(args)
关键字参数打包 def show(**kwargs): print(kwargs)
返回多个值 return a, b, c(自动打包为元组)
全局变量修改 global x; x += 1
匿名函数 lambda x, y: x + y
递归函数 def fact(n): return 1 if n==1 else n*fact(n-1)

常见错误排查指南

错误现象 大概率原因 解决方案
NameError: name 'x' is not defined 访问了未定义的变量 检查变量是否已赋值或作用域是否正确
UnboundLocalError: local variable 'x' referenced before assignment 函数内试图修改全局变量,但未用 global 声明 在修改前添加 global x
TypeError: func() missing 1 required positional argument 调用函数时参数数量不足 检查函数定义,传入所有必需的参数
TypeError: func() got an unexpected keyword argument 'x' 传入了函数不认识的形参名 检查形参名是否拼写正确
RecursionError: maximum recursion depth exceeded 递归函数没有正确的边界条件 检查边界条件是否可达到,或递归层数过大
返回值为 None 但期望有值 函数中没有 returnreturn 后没有值 添加正确的 return 语句

学习/生产最佳实践

  1. 单一职责原则:每个函数只做一件事,保持函数短小精悍(建议不超过 30~50 行)。如果一个函数做太多事,拆分成多个小函数。
  2. 文档字符串:为每个函数添加文档字符串,说明功能、参数和返回值。这在团队协作和后期维护中非常重要。
python 复制代码
def calculate_bmi(weight, height):
    """
    计算身体质量指数(BMI)

    参数:
        weight: 体重(公斤)
        height: 身高(米)

    返回:
        float: BMI 值
    """
    return weight / (height ** 2)
  1. 善用默认参数:为常用参数设置合理的默认值,提升函数的易用性。
  2. 避免修改全局变量:尽量通过参数传递和返回值与函数交互,而不是直接操作全局变量。这会使代码更可预测、更易测试。
  3. 递归 vs 迭代:递归代码更简洁,但存在性能开销和栈溢出风险。对于大规模数据,优先考虑迭代实现。
  4. 函数命名规范 :函数名应使用小写字母和下划线(如 get_user_info),动词开头,体现函数的行为。

🔜 下期预告

本期我们系统学习了函数的定义与调用、参数传递(位置/关键字/默认/打包/解包)、返回值、变量作用域(LEGB + global/nonlocal),以及递归函数和匿名函数(lambda)等高级用法,并通过角谷猜想、饮料自动售货机和归并排序三个实战项目,将函数式编程思想应用到实际场景中。

下一期 ,我们将进入 文件与数据格式化 的学习------掌握如何将程序中的数据持久化存储到文件中,学习文件的打开、读写、关闭操作,了解文本文件与二进制文件的区别,以及 CSV、JSON 等常见数据格式的读写方法。通过"文件备份工具"和"用户账户管理系统"等实战项目,让程序的数据真正"留得住"。敬请期待!


--- Compiled and Authored by Whisky --- July 14 th, 2026

相关推荐
网小鱼的学习笔记1 小时前
Agent学习001
学习·迁移学习
小小龙学IT1 小时前
Tigris:下一代无服务器数据库
数据库·云原生·serverless
茗创科技1 小时前
CGE连接组:用基因表达解码脑疾病的异质性(附高分文献下载)
python·matlab·脑网络
汤米粥1 小时前
Python调用百度搜索触发安全验证
开发语言·python
白帽小阳1 小时前
我的AI辅助开发工具链2026版:从编码到部署的全栈智能实践
网络·人工智能·学习·安全·自动化
杠杠的blog1 小时前
企业级提示词管理
python·agent·提示词·生产级实践
小小放舟、2 小时前
VS Code Code Runner 中文乱码修复与 IDEA 风格输出配置
vscode·python·code runner
有Li2 小时前
通过渐进式域变换实现组织分类的无监督单域泛化文献速递/基于多模态的医学影像分割与理解
人工智能·学习·分类·数据挖掘·文献·医学生
kdxiaojie2 小时前
Linux 驱动研究 —— V4L2 (2)
linux·运维·笔记·学习