【Python】基础语法入门(十一)—— 函数进阶:作用域、闭包与装饰器

在这里插入图片描述
在这里插入图片描述

🎯 说明:尽管《【Python】基础语法入门》系列原计划九篇完结,但许多读者反馈希望深入理解函数的高级特性。因此,本篇作为特别加更,聚焦 Python 函数的三大进阶概念:作用域(Scope)、闭包(Closure)和装饰器(Decorator)。这些内容虽属“中级”,却是写出优雅、灵活代码的关键!

你将学会:

  • 为什么变量有时“找不到”?——理解 LEGB 规则
  • 如何让函数“记住”外部状态?——闭包的妙用
  • 如何不修改原函数就增强功能?——装饰器实战

即使初次接触这些概念,本文也会用生活化例子 + 清晰代码带你轻松掌握。


1. 变量作用域(Scope)与 LEGB 规则

Python 中,变量并不是在任何地方都能被访问。它的可见范围由作用域决定。

四层作用域(LEGB):

层级含义示例
Local函数内部def f(): x = 1
Enclosing外层函数(嵌套函数)def outer(): x=1; def inner(): print(x)
Global模块顶层文件最外层的 x = 10
Built-in内置名称len, print, range

Python 按 L → E → G → B 顺序查找变量。

示例 1:全局 vs 局部

x = "全局变量"

def func():
    x = "局部变量"
    print("函数内:", x)  # 局部变量

func()
print("函数外:", x)      # 全局变量

✅ 局部变量不会影响全局变量。


示例 2:修改全局变量(global

count = 0

def increment():
    global count  # 声明使用全局变量
    count += 1

increment()
print(count)  # 1

⚠️ 少用 global!它会降低代码可读性和可测试性。


示例 3:嵌套函数与 nonlocal

def outer():
    x = "外层变量"
    
    def inner():
        nonlocal x  # 声明使用外层(非全局)变量
        x = "被 inner 修改"
        print("inner 中:", x)
    
    inner()
    print("outer 中:", x)

outer()
# 输出:
# inner 中: 被 inner 修改
# outer 中: 被 inner 修改

🔑 nonlocal 用于在嵌套函数中修改外层函数的局部变量


2. 闭包(Closure):函数的“记忆”能力

闭包是指:一个内部函数引用了外部函数的变量,即使外部函数已执行完毕,内部函数仍能访问这些变量。

生活比喻:

就像你租了一个带保险箱的房间。退房后,别人不能进房间,但你保留了保险箱钥匙,仍能取出里面的东西。

代码示例:

def make_multiplier(n):
    """返回一个乘法函数,该函数会记住 n"""
    def multiplier(x):
        return x * n  # 引用了外层变量 n
    return multiplier

# 创建两个闭包
double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5))   # 10
print(triple(5))   # 15

# 查看闭包保存的变量
print(double.__closure__[0].cell_contents)  # 2

闭包的三个条件

  1. 存在嵌套函数
  2. 内层函数引用了外层函数的变量
  3. 外层函数返回了内层函数

实战用途:

  • 配置化函数:如日志级别、API 基地址
  • 回调函数携带状态
  • 实现简单的工厂模式

3. 装饰器(Decorator):不侵入地增强函数

装饰器是 Python 最优雅的语法糖之一。它允许你在不修改原函数代码的前提下,为其添加新功能(如日志、计时、权限校验等)。

核心思想:

装饰器 = 接收一个函数 → 返回一个增强版函数

步骤 1:手动实现装饰逻辑

def say_hello():
    print("Hello!")

# 想给 say_hello 加上“执行时间”打印
def log_time(func):
    def wrapper():
        import time
        start = time.time()
        func()  # 调用原函数
        end = time.time()
        print(f"函数 {func.__name__} 耗时: {end - start:.4f} 秒")
    return wrapper

# 手动装饰
say_hello = log_time(say_hello)
say_hello()

步骤 2:使用 @ 语法糖(推荐)

import time

def log_time(func):
    def wrapper(*args, **kwargs):  # 支持任意参数
        start = time.time()
        result = func(*args, **kwargs)  # 获取返回值
        end = time.time()
        print(f"⏱️ {func.__name__} 耗时: {end - start:.4f}s")
        return result  # 返回原函数结果
    return wrapper

@log_time
def greet(name):
    time.sleep(0.1)  # 模拟耗时操作
    return f"你好, {name}!"

msg = greet("小明")
print(msg)
# 输出:
# ⏱️ greet 耗时: 0.1002s
# 你好, 小明!

✅ 关键点:

  • 使用 *args, **kwargs 让装饰器通用
  • 别忘了 return result,否则原函数返回值会丢失!

进阶:带参数的装饰器

有时我们希望装饰器本身也能接收参数,例如指定日志级别:

def log(level="INFO"):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"[{level}] 调用函数: {func.__name__}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@log(level="DEBUG")
def connect_db():
    print("连接数据库...")

connect_db()
# 输出:
# [DEBUG] 调用函数: connect_db
# 连接数据库...

结构:三层函数嵌套

  1. 最外层:接收装饰器参数
  2. 中间层:接收被装饰函数
  3. 最内层:替换原函数的逻辑

4. 常见内置装饰器

Python 自带几个实用装饰器:

@staticmethod / @classmethod

(已在面向对象篇介绍)

@property:将方法变为属性

class Circle:
    def __init__(self, radius):
        self._radius = radius
    
    @property
    def area(self):
        return 3.14159 * self._radius ** 2

c = Circle(5)
print(c.area)  # 78.53975 (像访问属性一样调用方法)

5. 总结与最佳实践

概念用途注意事项
作用域(LEGB)理解变量查找规则避免滥用 global
闭包让函数携带状态注意变量绑定问题(循环中创建闭包需谨慎)
装饰器无侵入式增强函数保留原函数元信息(可用 functools.wraps

补充:保留函数元信息

装饰后,原函数的 __name____doc__ 会变成 wrapper,可用 @functools.wraps 修复:

from functools import wraps

def my_decorator(func):
    @wraps(func)  # ← 关键!
    def wrapper(*args, **kwargs):
        """这是 wrapper 的 docstring"""
        return func(*args, **kwargs)
    return wrapper

@my_decorator
def example():
    """这是 example 的说明"""
    pass

print(example.__name__)  # example(不是 wrapper)
print(example.__doc__)   # 这是 example 的说明

下一步建议

  • 尝试写一个 缓存装饰器(用字典缓存函数结果)
  • 用闭包实现一个 计数器生成器
  • 在你的 To-Do List 项目中,为关键函数加上 日志装饰器

💡 装饰器和闭包是 Python 高阶编程的基石。掌握它们,你就离“Pythonic”代码更近了一步!

继续探索,代码世界因你而精彩! 🐍
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值