Python 进阶:递归函数的精髓与装饰器的妙用

目录

一、递归函数

1 函数结构

2 基本步骤

3 递归实例

二、装饰器

1 基本装饰器

2 带参装饰器

3 装饰器链

今日注意!!


一、递归函数

1 函数结构

递归函数通常由两个部分组成:

  1. 终止条件:用于确保递归能够停止,避免无限递归。

  2. 递归调用:函数在其内部调用自身,传递简化或减少的参数,以解决更小的子问题。

2 基本步骤

  1. 定义递归函数:在函数体内调用函数自身。

  2. 设定终止条件:确保递归能终止。

  3. 逐步简化问题:通过传递较小的参数递归求解,直至终止条件满足。

3 递归实例

  • 阶乘定义
  1. n! = n * (n-1) * (n-2) * ... * 1

  2. 递归公式:n! = n * (n-1)!,终止条件:0! = 1

def factorial(n):
    # 边界墙,回归条件
    if n == 1 or n == 0:
        return 1
    return n * factorial(n - 1)

print(factorial(5))  # 120

执行过程:

  • 斐波那契数列:

斐波那契数列(Fibonacci sequence)是一种经典的数列,它的特点是从第 3 项开始,每一项都等于前两项之和。前两项通常定义为:

  1. F(0) = 0

  2. F(1) = 1

从 F(2) 开始:

  1. F(2) = F(1) + F(0) = 1 + 0 = 1

  2. F(3) = F(2) + F(1) = 1 + 1 = 2

使用递归的思想实现斐波那契数列

# 写递归函数,先递归,再回归
def Fibonacci(n):
    # 边界墙:回归条件
    if n < 2:
        return n

    return Fibonacci(n - 1) + Fibonacci(n - 2)
    pass


print(Fibonacci(10))  # 55
  • 列表求和
  1. 递归思路:将列表分为 第一个元素 和 剩余元素,总和 = 第一个元素 + 剩余元素的和。
  2. 终止条件:当列表为空时,和为 0。
def sum_list(lst):
    # 终止条件
    if not lst:
        return 0
    return lst[0] + sum_list(lst[1:])


print(sum_list([1, 2, 3]))  # 6

二、装饰器

装饰器是Python对闭包思想的具体语法实现,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能。

  1. 日志记录:可以使用装饰器来记录函数的输入、输出或执行时间。

  2. 认证和授权:装饰器可以用于检查用户是否有权限执行特定操作。

  3. 缓存:装饰器可以缓存函数的结果,从而提高执行效率。

  4. 参数验证:可以使用装饰器来验证函数的输入参数是否符合预期。

  5. 代码注入:装饰器可以在函数的执行前后注入额外的代码。

1 基本装饰器

执行过程:

  • 装饰器初始化:
  1. decorator(say) 被调用,打印 …装饰器函数被调用…
  2. decorator 返回 wrapper 函数,say 变量现在指向 wrapper
  • wrapper开始执行:
  1. 记录开始时间并写入日志。
  2. 调用原始 say() 函数(休眠 3 秒)。
  3. 记录结束时间和执行时长,写入日志。
  4. 返回 say() 的结果 'Hello World!'

后续多次使用装饰器步骤与上述一致

import time


# 装饰器函数(闭包函数)  -- 可以多个地方调用,依次执行
def decorator(fn):
    print('…装饰器函数被调用…')

    def wrapper():
        # 时间戳:1970-01-01 00:00:00 到现在(毫)秒数
        start = time.time()
        # 1.通用的功能装饰器,比如日志记录、执行时间记录、CPU占用记录、GPU占用记录、内存占用记录
        with open('./log.txt', mode='a', encoding='utf-8') as f:
            f.write(f'{fn.__name__} 模型被调用……\n')
        # 2.被装饰的函数的核心功能,调用被装饰函数
        sun = fn()
        end = time.time()
        # 1.通用的功能装饰器,比如日志记录、执行时间记录、CPU占用记录、GPU占用记录、内存占用记录
        with open('./log.txt', mode='a', encoding='utf-8') as f:
            f.write(f'{fn.__name__} 模型被调用……执行时间:{end - start}\n')
        return sun
    return wrapper


# 应用装饰器,函数say作为装饰器的实参fn运行 -- decorator(say)
@decorator
def say():
    time.sleep(3)  # 休眠3秒
    return 'Hello World!'


# 真正调用的函数,是装饰器函数返回的函数
# 虽然调用say(),但实际上调用decorator(fn),fn指向say()
# decorator(fn)是闭包函数,外层函数返回内层函数,所以实际运行内层函数,返回也是内层函数
generator = say()
print(generator)


# deepseek大模型使用
@decorator
def DeepSeek():
    return 'DeepSeek模型使用...'

generator = DeepSeek()
print(generator)

2 带参装饰器

  • 三层结构
  1. 参数接收层params):接收装饰器参数(如 n=2),返回真正的装饰器 deep
  2. 装饰器层deep):接收被装饰函数(如 ttt),返回包装函数 warp
  3. 包装函数层warp):增强原函数功能(如记录调用次数),并调用原函数。
  • 等价转换
  1. 调用 params(2),打印 "打印次数:2",返回 deep 函数
  2. 执行 deep(ttt),返回 warp 函数
  3. ttt 变量指向 warp
  • 实际调用 warp('测试内容', temerator='0.5',high='199')

  1. x 从 1 递增到 2。
  2. 写入日志:ttt,2……
  3. 调用原函数 ttt('测试内容', temerator='0.5',high='199')
  • 原函数 ttt 的执行

  1. 遍历 kwargs
  2. 返回 ('测试内容', {'temerator': '0.5', 'high': '199'})
  • 返回结果

打印次数:2
('测试内容', )

# 带参装饰器
def params(n):
    print(f'打印次数:{n}')
    # 开始定义真正的装饰器函数
    def deep(fn):
        x = 1

        def warp(*args, **kwargs):
            nonlocal x
            x += 1
            with open('./demo.txt', mode='a', encoding='utf-8') as f:
                f.write(f'{fn.__name__},{x}……\n')
            get = fn(*args, **kwargs)  # 解包操作
            return get
        return warp
    return deep


# params(2):函数调用,返回值就是我们真正要用的装饰器函数
@params(2)  # deep(ttt)
def ttt(question, **kwargs):
    ff = {key: value for key, value in kwargs.items()}
    return question, ff
# 真正调用的函数,是装饰器函数返回的函数
generator = ttt('测试内容', temerator='0.5', high='199')
print(generator)

3 装饰器链

实际执行 wrapper2(),其内部调用 wrapper1(),最终调用原始 hello()

  • wrapper2 执行

  1. 调用 fn()(即 wrapper1),获取结果。
  2. 将结果转换为大写(upper())。
  • wrapper1 执行

  1. 调用 fn()(即原始 hello()),返回 'Hello World!'
  2. 反转结果并添加 ! → '!dlroW olleH'
  • 结果传递

  1. wrapper1 的结果 '!dlroW olleH' 被传递给 wrapper2
  2. wrapper2 将其转换为大写 → '!DLROW OLLEH'
def decorator1(fn):
    print('装饰器1……')
    print(f'装饰器1……{fn.__name__}')

    def wrapper(*args, **kwargs):
        result = fn(*args, **kwargs)
        return result[::-1] + '!'

    return wrapper


def decorator2(fn):
    print('装饰器2……')
    print(f'装饰器2……{fn.__name__}')

    def wrapper(*args, **kwargs):
        result = fn(*args, **kwargs)
        return result.upper()

    return wrapper


@decorator2  # decorator2(被decorator1装饰之后的函数)
@decorator1  # decorator1(hello)
def hello():
    return 'Hello World!'

print(hello())  # !DLROW OLLEH!

今日注意!!

对于装饰器的使用通常情况下都会调用python已写好的装饰器,以上对于装饰器的解释都是便于对装饰器的理解与思考。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值