12·模块三:函数入门

返回值与作用域(LEGB)

functionsreturnscope

第 12 课 - 返回值与作用域(LEGB)

课程模块: 模块三:函数 难度: Beginner 标签: functions, return, scope 上一课: 函数参数(位置、关键字、默认值) 下一课: Lambda 表达式与高阶函数


1. 学习目标

通过学习本课,你将能够:

  1. 熟练使用 return 语句从函数中返回一个或多个值。
  2. 理解 Python 作用域的概念,并区分局部变量和全局变量。
  3. 掌握变量查找的 LEGB 规则,解释为什么同名变量在不同地方会得到不同结果。
  4. 避免在函数内部错误地修改全局变量。
  5. 利用返回值将函数作为"黑盒"组件,构建更清晰、模块化的代码。

2. 核心概念

2.1 函数的"快递打包":返回值

函数不仅仅是为了执行一段代码,更像一个"加工厂"。我们给它原料(参数),它处理完后,需要把结果(产品)"打包"交还给我们。这个"打包"和"交还"的动作,就由 return 语句完成。

  • 没有返回值的函数:像一个没有产出的任务,执行完就结束了。
  • 有返回值的函数:执行后,会生成一个结果。这个结果可以是一个数字、一个字符串、一个列表,甚至是另一个函数。

2.2 变量的"房间":作用域 (Scope)

在 Python 中,变量就像放在不同"房间"里的东西。一个变量属于哪个"房间",决定了它在程序的哪些部分可以被访问。这就是作用域

  • 局部作用域 (Local): 函数内部定义的变量,只在本函数内可见。就像你卧室里的东西,只有你能轻易拿到。
  • 全局作用域 (Global): 在函数外部(通常是文件顶层)定义的变量,在整个文件的任何地方都可见。就像客厅里的东西,家里人都能看到。

2.3 变量的"寻宝地图":LEGB 规则

当在函数内使用一个变量名时,Python 会按照一个特定的顺序去查找它。这个顺序被称为 LEGB 规则,非常关键:

  1. L (Local): 先在当前函数的局部作用域内查找。
  2. E (Enclosing): 如果在嵌套函数中,则在外层函数的局部作用域内查找。
  3. G (Global): 在全局作用域(模块层级)内查找。
  4. B (Built-in): 最后在 Python 内置的名称中查找(如 len, print)。

如果这四个层级都找不到,就会抛出 NameError

3. 代码示例

示例 1:返回值的基础用法

def calculate_rectangle_area(length, width):
    """计算并返回矩形的面积。"""
    area = length * width
    return area  # 将计算结果"打包"返回

# 调用函数,并用一个变量来接收返回值
my_area = calculate_rectangle_area(5, 3)
print(f"矩形的面积是:{my_area}")  # 输出:矩形的面积是:15

# 返回值可以直接用于其他操作
total_cost = calculate_rectangle_area(4, 2) * 10  # 假设每平方单位10元
print(f"总成本是:{total_cost}")  # 输出:总成本是:80

示例 2:返回多个值

Python 可以轻松返回多个值,本质上是返回一个元组。

def get_user_info():
    """模拟获取用户信息,并返回姓名和年龄。"""
    name = "Alice"
    age = 25
    return name, age  # 返回一个元组 (name, age)

# 使用多个变量接收返回值
user_name, user_age = get_user_info()
print(f"姓名:{user_name}, 年龄:{user_age}")  # 输出:姓名:Alice, 年龄:25

# 也可以用一个变量接收整个元组
info = get_user_info()
print(info)  # 输出:('Alice', 25)

示例 3:LEGB 作用域演示

# 全局变量
global_var = "我在全局作用域 (G)"

def outer_function():
    # 外层函数的局部变量 (Enclosing)
    outer_var = "我在外层函数作用域 (E)"

    def inner_function():
        # 内层函数的局部变量 (Local)
        local_var = "我在内层函数作用域 (L)"
        # 此处可以访问 local_var, outer_var, global_var, 以及内置的 len
        print(local_var)
        print(outer_var)  # 符合 E 规则
        print(global_var) # 符合 G 规则
        print(len("内置函数")) # 符合 B 规则

    inner_function()
    # print(local_var)  # 错误!local_var 在此处不可见

outer_function()
# print(outer_var)  # 错误!outer_var 在此处不可见

4. 实践练习

练习 1:基础返回

编写一个函数 circle_area(radius),接受圆的半径作为参数,计算并返回其面积(使用公式 area = 3.14159 * radius ** 2)。

  • 调用函数,计算半径为 4 的圆的面积,并打印结果。
  • 预期输出圆的面积是:50.26544

练习 2:返回多个值

编写一个函数 analyze_numbers(a, b),接受两个数字,返回它们的(第一个减第二个)、乘积

  • 调用函数,传入数字 10 和 3,并分别打印出和、差、积。
  • 预期输出
    和:13
    差:7
    积:30
    

练习 3:作用域探险

以下代码的输出是什么?请先自己思考,再运行验证。

x = 10

def func1():
    x = 20
    print(f"func1 内部,x 的值是:{x}")

def func2():
    print(f"func2 内部,x 的值是:{x}")

def func3():
    global x  # 声明我们要修改全局变量 x
    x = 30
    print(f"func3 内部,x 的值是:{x}")

func1()
func2()
func3()
print(f"函数调用结束后,全局 x 的值是:{x}")
  • 思考并运行,解释每一行输出的原因。

5. 常见错误

  1. 忘记返回值

    def add(a, b):
        result = a + b
        # 忘记写 return result
    sum_val = add(2, 3)
    print(sum_val)  # 输出:None,因为函数没有返回任何东西。
    

    修正: 函数需要对外输出结果时,务必使用 return

  2. 在函数内错误地修改全局变量

    count = 0
    def increment():
        count = count + 1  # 错误!Python 会认为这行代码创建了一个新的局部变量 count,但初始化时引用了未赋值的局部变量。
        # 报错:UnboundLocalError: local variable 'count' referenced before assignment
    

    修正: 如果确需在函数内修改全局变量,使用 global 关键字声明:global count。但通常建议避免这么做,因为它会让代码状态变得难以追踪。更好的做法是将变量作为参数传入,并将新值返回。

  3. 混淆返回和打印

    def greet(name):
        print(f"Hello, {name}!")  # 这只是打印到屏幕,函数本身没有返回值。
    message = greet("Alice")  # message 的值是 None
    print(message + " Welcome!")  # 报错:TypeError,因为 None 不能和字符串相加。
    

    修正: 明确函数目的。如果函数是为了生成一个供后续程序使用的结果,请用 return。打印(print)只是让用户看到,不改变程序数据。

6. 小结

  • return 是函数的生命线: 它决定了函数"产出"什么,是函数与外界交换数据的核心方式。可以返回单个值,也可以返回用逗号分隔的多个值(元组)。
  • 作用域决定变量的可见性: 函数内部是"小房间"(局部作用域),函数外部是"大客厅"(全局作用域)。
  • LEGB 是变量查找的顺序图: 记住这个顺序,你就能解释大部分关于变量可见性的问题。它遵循"由内而外,就近原则"。
  • 最佳实践: 优先使用返回值和参数来在函数间传递数据,而不是依赖全局变量。这样代码更清晰、更易维护和调试。

理解返回值和作用域,是让你编写的函数从"执行命令"升级为"构建模块"的关键一步。现在,你的函数不仅能做事,还能有条理地汇报结果,并清晰地管理自己的"内部物品"了。

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「Lambda 表达式与高阶函数」 以巩固所学知识。