python的装饰器和闭包

python的装饰器和闭包

内容

Python 的装饰器是什么?

装饰器(Decorator)是 Python 中的一种用于扩展或修改函数/类行为的设计模式。它允许在不修改原有函数或类的情况下,动态地为其增加新的功能。这种功能在实践中非常有用,例如在日志记录、性能测试、权限控制、缓存等场景中。


装饰器的定义与使用

  1. 装饰器的基本结构是一个函数,它接收另一个函数作为参数,并返回一个新的函数。
  2. 使用装饰器时,通常通过 @decorator_name 的语法,将其作用于某个函数或方法。

简单示例:

def my_decorator(func):
    def wrapper():
        print("调用函数前的操作")
        func()
        print("调用函数后的操作")
    return wrapper

@my_decorator  # 等同于 say_hello = my_decorator(say_hello)
def say_hello():
    print("Hello, World!")

say_hello()

输出:

调用函数前的操作
Hello, World!
调用函数后的操作

解释:

  1. @my_decorator 装饰器将 say_hello() 函数传递给 my_decorator()
  2. my_decorator 返回一个新的函数 wrapper,该函数包装了原始的 say_hello()
  3. 当调用 say_hello() 时,实际执行的是 wrapper(),从而在调用原函数前后添加了新的行为。

带参数的装饰器:

如果被装饰的函数接受参数,那么 wrapper 函数也需要接受相应的参数:

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("调用函数前的操作")
        result = func(*args, **kwargs)
        print("调用函数后的操作")
        return result
    return wrapper

@my_decorator
def add(a, b):
    print(f"计算 {a} + {b}")
    return a + b

result = add(3, 5)
print(f"结果是: {result}")

输出:

调用函数前的操作
计算 3 + 5
调用函数后的操作
结果是: 8

解释:

  • 使用 *args**kwargs,确保装饰器可以支持任意参数的函数。

多个装饰器的使用:

多个装饰器可以层层叠加,执行顺序是从上到下应用装饰器:

def decorator1(func):
    def wrapper():
        print("执行 decorator1")
        func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("执行 decorator2")
        func()
    return wrapper

@decorator1
@decorator2
def say_hi():
    print("Hi!")

say_hi()

输出:

执行 decorator1
执行 decorator2
Hi!

解释:

  • @decorator1 包裹了 @decorator2,所以 decorator1 先执行。

装饰器的实际应用场景:

  1. 日志记录:
def log(func):
    def wrapper(*args, **kwargs):
        print(f"正在调用 {func.__name__} 函数")
        return func(*args, **kwargs)
    return wrapper

@log
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

输出:

正在调用 greet 函数
Hello, Alice!

  1. 权限控制:
def require_permission(permission):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if permission != "admin":
                print("权限不足,无法执行该操作")
                return
            return func(*args, **kwargs)
        return wrapper
    return decorator

@require_permission("user")
def delete_user():
    print("用户已删除")

delete_user()

输出:

权限不足,无法执行该操作

类装饰器:

除了装饰函数之外,装饰器还可以用于装饰类

def add_method(cls):
    cls.new_method = lambda self: print("这是新添加的方法")
    return cls

@add_method
class MyClass:
    pass

obj = MyClass()
obj.new_method()  # 调用装饰器添加的新方法

输出:

这是新添加的方法

总结:

  • 装饰器是一种强大的工具,可以动态地为函数或类添加功能。
  • 它们通过 @decorator 的语法,使代码更加简洁和易读。
  • 常见的应用场景包括:日志记录、权限控制、缓存、性能监控等。

理解装饰器的关键在于:装饰器本质上是高阶函数,它们接收一个函数或类并返回一个新的函数或类。装饰器的使用可以大大提高代码的复用性和可维护性

什么是闭包?

闭包(Closure)是指在内嵌函数中,引用了外部函数中的变量,并且即使外部函数执行完毕,这些变量仍然保存在内嵌函数的作用域中。这种结构使得函数能够“记住”其外部环境的变量。

闭包的核心在于:

  1. 函数嵌套:函数内部定义另一个函数。
  2. 外层函数的变量被内层函数引用
  3. 外层函数的作用域结束后,变量依然保存在内层函数中

闭包的简单例子

def outer_function(x):
    def inner_function(y):
        return x + y  # 内嵌函数引用了外部函数的变量 x
    return inner_function  # 返回内嵌函数

closure = outer_function(10)  # outer_function 执行完毕,返回 inner_function
result = closure(5)  # 相当于调用 inner_function(5)
print(result)  # 输出: 15

解释:

  1. outer_function 接受一个参数 x,并定义了一个内嵌函数 inner_function
  2. inner_function 使用了外部函数 outer_function 中的变量 x
  3. outer_function 执行完毕后,返回 inner_function 函数对象。
  4. 虽然 outer_function 的作用域已经结束,但由于 inner_function 是闭包,它保留了对变量 x 的引用。

闭包的作用

  • 保存状态:闭包可以记住函数的某些状态,即使外部作用域已经结束。
  • 延迟执行:闭包可以延迟计算或操作,直到真正需要时才执行。
  • 函数式编程的基础:在某些语言中(如 Python、JavaScript),闭包是实现回调、装饰器等模式的重要基础。

闭包与作用域的关系

让我们再看一个涉及作用域的闭包示例:

def counter():
    count = 0  # 外部变量

    def increment():
        nonlocal count  # 使用 nonlocal 声明引用外层作用域中的变量
        count += 1
        return count

    return increment

counter_fn = counter()  # 返回内嵌的 increment 函数
print(counter_fn())  # 输出: 1
print(counter_fn())  # 输出: 2
print(counter_fn())  # 输出: 3

解释:

  • counter 函数创建了一个变量 count,并返回一个 increment 内嵌函数。
  • 每次调用 increment 时,都会更新并返回count 的值
  • 由于 increment 是闭包,它可以访问外部函数的变量 count,即使 counter 已经执行完毕。

闭包的常见应用:

1. 装饰器:

装饰器本质上就是闭包,封装了原函数及其状态。

def multiply_by(factor):
    def decorator(func):
        def wrapper(*args, **kwargs):
            return factor * func(*args, **kwargs)
        return wrapper
    return decorator

@multiply_by(2)
def add(a, b):
    return a + b

print(add(3, 5))  # 输出: 16

解释:

  • 装饰器 multiply_by(2) 创建了一个闭包,将 factor=2 存在 wrapper 中。
  • 当调用 add(3, 5) 时,装饰器将结果乘以 2

2. 回调函数:

闭包常用于异步编程中的回调函数,保存状态直到异步操作完成。


总结:

闭包(Closure)是函数的一种特性,使得内嵌函数可以“记住”外部函数的变量,即使外部函数已经执行完毕。这种特性使得闭包在编程中非常有用,尤其是在处理状态保存、装饰器和回调函数时。

关键点:

  1. 内嵌函数引用外部函数中的变量。
  2. 外部函数执行完毕后,内嵌函数仍然可以使用这些变量。
  3. nonlocal 关键字允许内嵌函数修改外部作用域中的变量。

闭包不仅使代码更加简洁,还能实现强大的功能,是 Python 编程中的重要概念。

posted @ 2024-10-20 00:11  Gold_stein  阅读(9)  评论(0编辑  收藏  举报