闭包和装饰器

引子

内部函数和外部函数之间的关系在于内部函数被嵌套在外部函数内。

这种嵌套关系使得内部函数能够访问外部函数的变量,形成了闭包,提供了一种有趣而强大的编程模式。这种嵌套关系使得内部函数能够访问外部函数的变量,形成了闭包,提供了一种有趣而强大的编程模式。
like this:

def outer_function(x):
    # 内部函数
    def inner_function(y):
        return x + y
    return inner_function

# 创建闭包
closure_example = outer_function(10)

# 使用闭包
result = closure_example(5)
print(result)  # 输出15

在这个例子中,outer_function是外部函数,它接受一个参数 x。在外部函数内,有一个内部函数 inner_function,它引用了外部函数的参数 x。当 outer_function(10) 被调用时,它返回了内部函数的引用,形成了闭包。这个闭包被赋值给变量 closure_example

然后,我们调用闭包 closure_example(5),这实际上调用了内部函数,并传递了参数 y。由于内部函数引用了外部函数的变量 x,所以它可以访问并使用 x 的值,最后返回 x + y 的结果。在这个例子中,结果是 15。

再看个闭包栗子👇

# 定义闭包函数
def my_decorator(func):
    # 内部函数,接受任意参数并传递给原始函数
    def wrapper(*args, **kwargs):
        print("在函数调用之前, 做一些事情")
        # 调用原始函数
        result = func(*args, **kwargs)
        print("在函数调用之后, 做一些事情")
        return result
    return wrapper

def say_hello(name):
    print(f"Hello, {name}!")

outer = my_decorator(say_hello)
outer("sunshine")

代码运行结果如下:
python wrapper.py
在这个例子中,my_decorator是一个外部函数,它接受一个函数func作为参数,并返回一个新的函数 wrapperwrapper是一个闭包,它引用了外部函数 my_decorator的参数 func。在 wrapper 中,我们可以在原始函数调用之前和之后添加额外的操作。

换个写法

# 定义装饰器函数
def my_decorator(func):
    # 内部函数,接受任意参数并传递给原始函数
    def wrapper(*args, **kwargs):
        print("在函数调用之前, 做一些事情")
        # 调用原始函数
        result = func(*args, **kwargs)
        print("在函数调用之后, 做一些事情")
        return result
    return wrapper

# 使用装饰器
@my_decorator
def say_hello(name):
    print(f"Hello, {name}!")

# 调用被装饰后的函数
say_hello("Alice")

是的,这就是装饰器。对比一下@写法与闭包写法,瞬间了然,就是换个写法。

装饰器传参

# 装饰器工厂函数,接受参数
def my_decorator_factory(prefix):
    # 实际的装饰器函数,接受被装饰的函数作为参数
    def my_decorator(func):
        # 内部函数,接受任意参数并传递给原始函数
        def wrapper(*args, **kwargs):
            print(f"{prefix}: 在函数调用之前, 做一些事情")
            # 调用原始函数
            result = func(*args, **kwargs)
            print(f"{prefix}: 在函数调用之后, 做一些事情")
            return result
        return wrapper
    return my_decorator

# 使用装饰器工厂创建装饰器


@my_decorator_factory(prefix="DEBUG")
def say_hello(name):
    print(f"Hello, {name}!")


# 调用被装饰后的函数
say_hello("Alice")

装饰器传参

在这个例子中my_decorator_factory是一个装饰器工厂函数,它接受一个参数prefix。这个工厂函数返回了实际的装饰器函数my_decorator,而my_decorator返回了内部函数wrapper

当我们使用@my_decorator_factory("DEBUG")语法应用装饰器时,实际上是调用了装饰器工厂函数,将参数"DEBUG"传递给它,得到了装饰器函数my_decorato

然后,my_decorator被应用于 say_hello函数。

当调用 say_hello("Alice") 时,实际上是调用了经过装饰后的函数 wrapper。这样,我们可以在装饰器内部使用传递的参数,实现更加灵活的装饰器行为。

总结

函数装饰器是 Python 中一种强大的工具,主要用于修改或扩展函数的行为。装饰器可以在不改变原始函数代码的情况下,动态地为函数添加额外的功能或修改其行为。以下是一些常见的装饰器的作用:

  1. 代码重构: 装饰器可以将一些通用的行为封装在一个函数中,然后通过装饰器应用到多个函数上,实现代码重用。
  2. 日志记录:装饰器可以用于记录函数的调用信息,如输入参数、执行时间等,用于调试或日志记录。
  3. 性能分析:装饰器可以用于测量函数的执行时间,帮助进行性能分析。
  4. 权限控制:装饰器可以用于检查用户权限或其他条件,并决定是否允许执行函数。

示例

  1. 代码重构

    def my_decorator(func):
     def wrapper(*args, **kwargs):
         print("Something is happening before the function is called.")
         result = func(*args, **kwargs)
         print("Something is happening after the function is called.")
         return result
     return wrapper

    我们可以将此装饰器作用于不同函数

    @my_decorator
    def say_hello(name):
     print(f"Hello, {name}!")
    @my_decorator
    def say_goodbye(name):
     print(f"Goodbye, {name}!")
  2. 日志记录

    def log_decorator(func):
     def wrapper(*args, **kwargs):
         print(f"调用 {func.__name__} 的参数是: {args}, kwargs: {kwargs}")
         result = func(*args, **kwargs)
         print(f"{func.__name__} 返回值是: {result}")
         return result
     return wrapper
    @log_decorator
    def add(x, y):
     return x + y
  3. 性能分析

    import time
    def timing_decorator(func):
     def wrapper(*args, **kwargs):
         start_time = time.time()
         result = func(*args, **kwargs)
         end_time = time.time()
         print(f"{func.__name__} 花费了 {end_time - start_time} 秒")
         return result
     return wrapper
    @timing_decorator
    def slow_function():
     time.sleep(2)
     print("函数执行结束")
  4. 权限控制

    def permission_required(permission):
     def decorator(func):
         def wrapper(*args, **kwargs):
             if check_permission(permission):
                 return func(*args, **kwargs)
             else:
                 print("权限未通过")
         return wrapper
     return decorator
    @permission_required("admin")
    def admin_function():
     print("Admin function executed.")

每日一句:有什么胜利可言,挺住意味着一切。 –里尔克

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
文章
1
粉丝
1
喜欢
0
收藏
0
排名:3490
访问:39
私信
所有博文
社区赞助商