" name="sm-site-verification"/>
侧边栏壁纸
博主头像
PySuper 博主等级

千里之行,始于足下

  • 累计撰写 206 篇文章
  • 累计创建 14 个标签
  • 累计收到 2 条评论

目 录CONTENT

文章目录

Python 闭包 装饰器

PySuper
2024-06-19 / 0 评论 / 1 点赞 / 158 阅读 / 0 字
温馨提示:
本文最后更新于2024-08-28,若内容或图片失效,请留言反馈。 所有牛逼的人都有一段苦逼的岁月。 但是你只要像SB一样去坚持,终将牛逼!!! ✊✊✊

使用 () 调用函数时,主要发生的事情包括查找函数对象、创建调用帧(包含了函数的局部变量和执行环境等信息)、参数传递、执行函数体和返回值(如果函数没有显式地返回值,它会隐式地返回 None

这一过程使得我们能够动态调用和执行函数

  • 函数式编程

  • 代码重用

闭包

基本概念

闭包(Closure)是指一个函数内部定义的函数,并且这个内部函数能够引用外部函数中的变量,即使外部函数已经执行完毕。

特点:

  • 嵌套函数:闭包必须有一个内部函数

  • 自由变量:内部函数使用外部函数的变量

  • 返回内部函数外部函数返回内部函数的引用

inner_function就是一个闭包,因为它引用了外部函数outer_function的变量message

正常来说,调用一个函数的时候,这个函数中的所有局部变量和形参,都只会在这个函数执行的过程中才会保留,只要这个函数执行完毕,这些局部变量和形参就会被自动释放,也就是没有了。

闭包比普通函数强大的地方在于,它在外部函数执行完毕之后,这个外部函数中的所有局部变量和形参,都不会被释放,而是等到内部函数执行完毕,以便于调用内部函数的时候可以使用。

  • 好处:可以将局部变量永久存储

  • 坏处:占用内存

    • 普通函数:[A() for i in range]循环一次 释放一次,100次也只有一次的A()数据

    • 闭包函数:[B() for i in range]数据一直保存在内存中,每次循环都会创建新的 保存下来

def outer_function(msg):
    message = msg

    def inner_function():
        print(message)

    return inner_function


closure = outer_function("Hello, World!")

closure()

nonlocal

在嵌套函数中修改外部非全局变量。它告诉Python解释器,在当前作用域内寻找该变量,而不是在局部作用域内定义一个新变量

def outer_function():
    count = 0

    def inner_function():
		# 表示 count 不是局部变量,而是外部函数 outer_function 中的变量
		# 每次调用 inner_function 时,它都会修改 outer_function 中的 count 变量
        nonlocal count
        count += 1
        print(count)

    return inner_function

closure = outer_function()

closure()  # 输出: 1
closure()  # 输出: 2
closure()  # 输出: 3

多个内部函数

一般还是只写一个内部函数

def counter_operations(initial_count):
    count = initial_count

    def increment():
        nonlocal count
        count += 1
        return count

    def decrement():
        nonlocal count
        count -= 1
        return count

    return increment, decrement

# 创建闭包
increment_func, decrement_func = counter_operations(10)

# 使用闭包
print(increment_func())  # 输出: 11
print(increment_func())  # 输出: 12
print(decrement_func())  # 输出: 11
print(decrement_func())  # 输出: 10

外部函数变量

  • 闭包中,外部函数的变量,不会被立即销毁(便于内部函数调用)

  • 可以重复使用外部函数变量,或者是不断覆盖,不断使用 赋值 之后的外部函数变量

def create():

    # 定义坐标原点
    pos = [0, 0]

    def player(direction, step):
        # 这里的pos是全局变量, new_x,new_y是局部变量,局部变量会覆盖全局变量
        new_x = pos[0] + step * direction[0]
        new_y = pos[1] + step * direction[1]

        # 外部函数中的变量,不会立即销毁,这里用new_x/new_y覆盖了 外部函数的变量
        # 下一次进入函数的时候,使用的就是 外部函数中的变量,值 却是上一次修改的值
        pos[0] = new_x
        pos[1] = new_y
        return pos

    return player


player = create() # 返回的是 player 函数

print(player([1, 0], 10))
print(player([0, 1], 20))
print(player([-1, 0], 20))

装饰器

装饰器(Decorator)是一种高级函数,用于在不改变函数本身的情况下,扩展或修改其功能

装饰器本质上是一个返回函数的函数

装饰器通过使用@decorator_name语法来应用

示例:

def decorator_function(original_function):
    def wrapper_function(*args, **kwargs):
        print(f"Wrapper executed this before {original_function.__name__}")
        return original_function(*args, **kwargs)

    return wrapper_function


@decorator_function
def display():
    print("Display function ran")


display()

@decorator_function是装饰器,它会修改display函数的行为,使其在执行原始函数之前打印一条信息

无参数

def decorator(func: Callable):
    def wrapper(*args, **kwargs):
        print('before')
        func(*args, **kwargs)
        print('after')

    return wrapper


@decorator
def double(x: int):
    print(f"func: {x * 2}")

duble(10)


before
func: 20
after

有参数

ıdef repeat(num_times):
    def decorator_repeat(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator_repeat

@repeat(num_times=3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")


Hello, Alice!
Hello, Alice!
Hello, Alice!
def my_decorator(arg1, arg2):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print("在原函数前执行,参数为:", arg1, arg2)
            result = func(*args, **kwargs)
            print("在原函数后执行,参数为:", arg1, arg2)
            return result
        return wrapper
    return decorator

@my_decorator("hello", "world")
def say_hello(name):
    print(f"{name}!")

say_hello("Tom")


在原函数前执行,参数为: hello world
Tom!
在原函数后执行,参数为: hello world

注意事项

  • 装饰器的执行顺序是从内到外,即先执行最内层的装饰器,再执行外层的装饰器

  • 装饰器可以用于类方法、静态方法等,但通常用于普通函数

from typing import Callable


def duble(x: int) -> None:
    """
    Python中的函数,其实是用一个变量,里面保存了一个函数对象
    """
    print(x * 2)


def tripele(x: int):
    """三倍"""
    return x * 3


def call_num(func: Callable, num: int):
    """
    调用一个函数
    这里是把传进来的参数,带到func里面去执行,那么func里面只需要拿着这个参数,去操作就可以了
    如果有返回值,我们再用变量去接收这个变量
    我们可以直接打印func(num),但是其返回值是None,是因为我们再func里面没有返回任何东西,Python就默认返回None了
    如果func里面返回数据了,我们就可以接受这个数据,如tripele()
    """
    func(num)
    result = func(num)
    return result


# call_num(duble, 10)
result = call_num(tripele, 20)
print(result)

#####################################################

def get_multiple_func(num):
    """这里返回的是一个函数应用"""
    def multiple(x: int) -> int:
        """在这里操作了变量"""
        return x * num

    return multiple

double = get_multiple_func(2)
triple = get_multiple_func(3)

print(double(10))
print(triple(10))

两者比较

装饰器通常利用闭包来实现

装饰器的内部函数(wrapper function)引用了装饰器外部函数的变量(如原始函数),从而形成闭包

  • 闭包:用于保存函数的环境,使得内部函数可以记住和访问外部函数的变量

  • 装饰器:用于动态地修改或扩展函数的行为,通常通过闭包实现

1
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区