【Python】Python函数的黑魔法:递归,嵌套函数与装饰器

欢迎来到CILMY23的博客

本篇主题为: Python函数的黑魔法:递归,嵌套函数与装饰器

个人主页:CILMY23-CSDN博客

系列专栏:Python | C++ | C语言 | 数据结构与算法

感谢观看,支持的可以给个一键三连,点赞关注+收藏。


写在前头:

本期主要补充上篇未完成的内容,(点击链接跳转)其中包括参数传递中序列解包,递归函数和嵌套函数,以及python中重要的概念————装饰器 ,除此之外还会扩展一些python中的作用域概念


目录

一、参数传递的序列解包

二、递归函数和嵌套函数

2.1 递归函数

2.2 嵌套函数

三、装饰器

3.1 装饰器的概念

3.2 装饰器的定义和使用

3.3 装饰器的应用场景

四、变量的作用域

4.1 变量类型

4.2 global关键字和nonlocal

global关键字

nonlocal关键字


一、参数传递的序列解包

参数传递的序列解包是指在函数调用时,将一个序列(如列表、元组等)进行解包,然后将解包后的内容作为参数传递给函数。这使得我们可以使用序列中的元素来作为函数的参数,而不必一个个地手动传递。

例如:

def func(x,y,z):
    return x + y +z

print(func(*[1,2,3]))
print(func(*(5,9,8)))

我们在上一篇中说,* args是将接收的多个参数放在一个元组里,那 * 其实是将一个序列中的元素解包出来,分别传递给形参中的各个变量。那 ** 就是将字典的各个元素传递给形参中的多个变量

 例如:

# 定义函数2
def func2(name, age):
    print(f"Name: {name}, Age: {age}")

# 创建人的字典
person = {'name': 'Alice', 'age': 25}

# 将字典通过**解包传递给函数2
func2(**person)

注意:字典中的"键---值"和形参在名称和个数必须一一对应 

二、递归函数和嵌套函数

 递归函数和嵌套函数,它们都是 Python 编程中非常重要的概念,接下来我们就详细看看吧

2.1 递归函数

如果一个函数在函数体中直接或间接调用自身,那么这个函数就被称为递归函数。简单来说,这个函数在调用的时候会调用自身,直到结束。

Python允许使用递归函数。如果函数 a 中调用函数 a 自身,则称为直接递归。如果函数 a 在内部调用了函数 b,在函数 b 中又调用函数 a,则称为间接递归

递归函数的思想是"将一个大问题分解为一个或多个与原问题形式相似但规模较小的子问题来解决"。函数会不断地调用自身来解决这些子问题,直到达到了结束条件,从而结束递归的过程。

例如:求斐波那契数列前十项

# 递归函数
def Fib(n):
    if n < 2:
        return 1  # 第1,2个斐波那契数为1
    else:
        return Fib(n-1) + Fib(n-2)  # 递推关系:前两个斐波那契数之和

# 输出前10个斐波那契数
for i in range(10):
    print(Fib(i),end=" ")

结果: 

 

解析:

当使用递归函数来解决斐波那契数列时,可以通过递归的方式来计算第n个斐波那契数。斐波那契数列的定义如下:

  • 第1个斐波那契数为1
  • 第2个斐波那契数为1
  • 从第2个数开始,后续的每个斐波那契数都是前两个斐波那契数之和

练习题:使用递归函数解决1+2+……+n的和。(答案在文章末尾) 

2.2 嵌套函数

嵌套函数指的是在一个函数内部定义另一个函数。其中,外部定义函数称为外函数,内部定义的函数称为内函数,嵌套函数在外部函数中具有局部作用域,它可以访问外部函数的变量。

例如:

# 嵌套函数
def outer_function(x):
    def inner_function(y):
        return y * 2

    return inner_function(x)  # 调用内部函数


result = outer_function(5)  # 调用外部函数
print(result)  # 输出 10

三、装饰器

装饰器是一种Python编程语言的特性,那具体的我们接着往下看吧

3.1 装饰器的概念

装饰器(Decorator)是用来包装函数的函数。装饰器是一种语法,允许在不修改函数原始代码的情况下,动态地添加功能或修改函数的行为。

装饰器基于函数,基本原理是将一个函数作为参数传递给另一个函数,然后返回一个新的函数。这个新函数通常用来包裹原始函数,并在执行原始函数前后执行一些额外的代码。

3.2 装饰器的定义和使用

定义装饰器的一般格式为:

def decorator(func):
    pass

@decorator
def func():
    pass

其中,decorator 为装饰器。@decorator 为函数的装饰器修饰符。func 为装饰器的函数对象参数。装饰器可以返回一个值,也可以返回一个函数,还可以返回一个装饰器或其他对象。

例如:装饰器返回一个函数

# 装饰器返回一个函数
def my_decorator(func):
    def wrapper():
        return func() + 1
    return wrapper

def my_function():
    return 3

my_function = my_decorator(my_function)

result = my_function()
print(result)  # 输出 4

 代码解析:

当调用 my_function() 时,实际上我们是在用装饰器 my_decorator,而 my_function 替代了 func

装饰器中嵌套了 wrapper() 函数,并且返回值是 wrapper ,所以实际上我们就是调用了 wrapper()这个函数,并将这个函数的返回值作为装饰器的返回值传递。

所以计算就是 3+1 = 4

 例如:装饰器返回一个装饰器

# 装饰器返回一个装饰器
def outer_decorator(option):
    if option == "A":
        def inner_decorator(func):
            def wrapper():
                return func()

            return wrapper
    elif option == "B":
        def inner_decorator(func):
            def wrapper():
                return func()

            return wrapper
    else:
        raise ValueError("Invalid option")

    return inner_decorator


@outer_decorator(option="A")
def ret1():
    return "Hello, world!"


@outer_decorator(option="B")
def ret2():
    return "Hello again!"


print(ret1())
print(ret2())

 代码解析:

外部装饰器 outer_decorator 会根据 option 的不同,选择不同的装饰器 inner_decorator(func),然后将外部函数替换掉 func , 最后返回装饰器 inner_decorator,像上述案例,如果有装饰器嵌套装饰器,就被称为多重装饰器

3.3 装饰器的应用场景

 例如:修改网页的文本格式

# 修改网页的文本格式
# 定义装饰器
def deco(func):
    # 定义内函数
    def modify_text(str):
        return "<strong>" + func(str) + "</strong>"

    return modify_text


# 使用装饰器修饰函数
@deco
def textFunc(str):
    return str


print(textFunc("text"))

四、变量的作用域

4.1 变量类型

  1. 局部变量和局部作用域 L(Local):定义在函数内部的变量。局部变量的作用域是从函数内定义它的位置到结束。当函数被调用时创建一个新的局部变量,函数调用完成后,局部变量就消失了。

  2. 全局变量和全局作用域G(Global):在模块的函数外定义的变量。在模块文件顶层声明的变量具有全局作用域。从外部看,模块的全局变量就是一个模块对象的属性。全局作用域的作用范围仅限于单个模块文件内。

  3. 嵌套变量和嵌套作用域E(Enclosing):定义在嵌套函数的外函数内、内函数外的变量。嵌套作用域为嵌套函数内定义它的位置开始的整个函数内。

  4. 内建变量和内建作用域B(Built-in):系统内固定模块里定义的变量,一般为预定义在内建模块内的变量。

例如:

# 四、变量作用域
global_v = "我是一个全局变量"


def outer_function():
    enclosing_v = "我是一个嵌套变量"

    def inner_function():
        local_v = "我是一个局部变量"
        print(local_v)
        print(enclosing_v)
        print(global_v)

    inner_function()


outer_function()
print(global_v)

 在Python中,当程序执行中要使用一个语句中的变量时,就会按照 L -> E -> G -> B 的规则在程序中查找这个变量的定义,即在局部范围中找不到,便会去局部范围外查找,然后去全局变量以此类推。

4.2 global关键字和nonlocal

global关键字

当在函数内部想要修改全局作用域的变量时,可以使用global关键字来声明变量。这样就可以在函数内部修改全局变量的值。

# global 关键字

global_var = 10


def modify_global():
    global global_var
    global_var = 20


modify_global()
print(global_var)  # 输出 20

结果:打印20 

nonlocal关键字

nonlocal关键字用于在一个嵌套函数中修改嵌套作用域 E 的变量。当在内部函数中想要修改上一层函数中的变量时,可以使用nonlocal关键字。

# nonlocal 关键字
def outer_function():
    outer_var = 10

    def inner_function():
        nonlocal outer_var
        outer_var = 20

    inner_function()
    print(outer_var)  

outer_function()

 结果:输出20


   总结:

  • * 用于序列解包,** 用于字典解包
  • 递归函数的核心是将一个大问题拆解成无数子问题
  • 装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。
  • 装饰器也可以嵌套装饰器,从而选择不同的效果

感谢各位同伴的支持,本期python篇就讲解到这啦,如果你觉得写的不错的话,可以给个一键三连,点赞关注+收藏,若有不足,欢迎各位在评论区讨论。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/571115.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

redis基于Stream类型实现消息队列,命令操作,术语概念,个人总结等

个人大白话总结 1 在Redis Stream中&#xff0c;即使消息被消费者确认&#xff08;acknowledged, ACK&#xff09;&#xff0c;消息也不会自动从Stream数据结构中删除。这与Kafka或RabbitMQ等传统消息队列系统的做法不同&#xff0c;在那些系统中&#xff0c;一旦消息被消费并…

废液收集系统物联网远程监控解决方案

废液收集系统物联网远程监控解决方案 在面对日益严峻的环保压力和严格的法律法规要求下&#xff0c;构建一套高效、智能的废液收集系统物联网远程监控解决方案显得尤为重要。该方案旨在通过深度融合物联网技术、云计算、大数据分析等先进手段&#xff0c;实现对废液收集系统的…

RuoYi-Vue-Plus (SaToken 注解鉴权)

一、SaInterceptor 注解鉴权和路由拦截鉴权 拦截器&#xff1a;SaInterceptor 实现类位置&#xff1a; cn.dev33.satoken.interceptor.SaInterceptor 功能&#xff1a;Sa-Token 综合拦截器&#xff0c;提供注解鉴权和路由拦截鉴权能力 /*** 创建一个 Sa-Token 综合拦截器&…

测试用例设计方法-异常测试

飞的最高的海鸥&#xff0c;能看到最远的奇景。大家好&#xff0c;继续给大家分享如何进行异常测试&#xff0c;首先要做好异常测试&#xff0c;需要我们对被测系统进行全面的了解&#xff0c;熟悉被测系统的功能、架构和运行机制&#xff0c;然后在这个基础上尽可能覆盖各种的…

再谈“协议”

1.认识协议 之前我们使用TCP的方式实现了一个服务器&#xff0c;而TCP是面向字节流的&#xff0c;而UDP是面向数据报的&#xff0c;接下来通过一个例子区分两种的区别。 UDP面向数据报&#xff1a;就如同发快递&#xff0c;你发多少个快递&#xff0c;对面就收到多少个快递&am…

探索React Router:实现动态二级路由

我有一个路由配置的二维数组&#xff0c;想根据这个数组结合路由组件来动态生成路由&#xff0c;应该怎么样实现。在 React Router 6 中渲染二级路由的方式跟 React Router 65相比有一些变化,但核心思路仍然是利用 Route 组件和路由嵌套的方式。下面是具体的步骤: 定义路由数组…

OpenCompass 大模型评测实战——作业

OpenCompass 大模型评测实战——作业 一、基础作业1.1、使用 OpenCompass 评测 internlm2-chat-1_8b 模型在 C-Eval 数据集上的性能1.1.1、安装基本环境1.1.2、解压数据集1.1.3、查看支持的数据集和模型1.1.4、启动评测 二、进阶作业2.1、将自定义数据集提交至OpenCompass官网 …

WIFISKY 7层流控路由器 confirm.php RCE漏洞复现

0x01 产品简介 WIFISKY-7层流控路由器是一款可用于家庭或办公环境的无线路由器,具备流控功能以优化网络流量和提供更稳定的网络连接。该路由器采用了7层流控技术,能够依据网络数据包的内容进行智能管理,从而实现对网络流量的精细化控制和优化。这种技术可以提升网络的整体性…

vscode 使用文件模板功能来添加版权信息

vscode 新建文件的时候&#xff0c;自动填充作者及版权信息 无需使用插件&#xff0c;操作如下&#xff1a; 选择 “首选项(Preferences)”。在搜索框中输入 “file template” 或者 “文件模板”&#xff0c;然后选择相关的设置项。 {"C_Cpp.clang_format_fallbackSt…

ctfshow web入门 SQl注入 web191--web200

web191 多了一个正则绕过 上脚本布尔盲注 用ord #author:yu22x import requests import string url"http://70adf0cb-2208-4974-b064-50a4f4103541.challenge.ctf.show/api/index.php" sstring.ascii_lettersstring.digits flag for i in range(1,45):print(i)for j…

【熵与特征提取】从近似熵,到样本熵,到模糊熵,再到排列熵,包络熵,散布熵,究竟实现了什么?(第六篇)——“散布熵”及其MATLAB实现

今天讲散布熵&#xff0c;之前用了几篇文章分别讲述了功率谱熵、奇异谱熵、能量熵、近似熵、样本熵、模糊熵、排列熵、包络熵这8种类型的熵&#xff1a; Mr.看海&#xff1a;【熵与特征提取】基于“信息熵”的特征指标及其MATLAB代码实现&#xff08;功率谱熵、奇异谱熵、能量…

脚手架搭建项目package.json配置中依赖的版本问题

脚手架搭建项目package.json配置中依赖的版本问题 问题描述&#xff1a;项目刚搭建好&#xff0c;运行没有问题&#xff0c;为什么过一段时间&#xff0c;删除node_modules&#xff0c;或者重新安装包依赖&#xff0c;然后项目某些地方出现莫名的错误&#xff08;依赖库的地方…

希捷HDD最新财报:销售同比下降11%,环比增长6%,4Q24前景看好

Seagate Technology Holdings plc公布了截至2024年3月29日的第三财季财务业绩。 “随着云需求改善、我们强大的运营纪律和价格执行&#xff0c;希捷3月季度的营收增长了6%&#xff0c;非GAAP每股收益较上一季度翻了一番多。这种组合为我们市场复苏时回归目标利润率奠定了基础。…

C++:类与对象完结篇

hello&#xff0c;各位小伙伴&#xff0c;本篇文章跟大家一起学习《C&#xff1a;运算符重载》&#xff0c;感谢大家对我上一篇的支持&#xff0c;如有什么问题&#xff0c;还请多多指教 &#xff01; 文章目录 重新认识构造函数1.初始化列表2.explicit关键字 static成员1.sta…

面试:ThreadLocal

目录 1、ThreadLocal可以实现〔资源对象】的线程隔离&#xff0c;让每个线程各用各的【资源对象】&#xff0c;避免争用引发的线程安全问题 2、ThreadLocal同时实现了线程内的资源共享 3、原理 4、为什么ThreadLocalMap 中的 key (即 ThreadLocal &#xff09;要设计为弱引用…

configure: error: library ‘crypto‘ is required for OpenSSL

1、执行命令./configure --prefix/usr/local/pgsql/postgresql-14.2 --with-openssl 报错configure: error: library crypto is required for OpenSSL 2、解决办法 yum install openssl openssl-devel

pom文件依赖报红问题

dependencyManagement标签下依赖报红 如图 dependencyManagement标签下依赖报红问题&#xff0c;原因是dependencyManagement标签下的包不会被下载&#xff0c;repository里根本没有 解决方法 &#xff1a;将依赖复制到dependencies标签下&#xff0c;再reload pom文件&#x…

Leetcode算法训练日记 | day35

专题九 贪心算法 一、柠檬水找零 1.题目 Leetcode&#xff1a;第 860 题 在柠檬水摊上&#xff0c;每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品&#xff0c;&#xff08;按账单 bills 支付的顺序&#xff09;一次购买一杯。 每位顾客只买一杯柠檬水&#xff0c;然…

为什么建议游戏工作室使用海外住宅IP防封?

当谈到游戏工作室时&#xff0c;它们通常以多开游戏账号来获取收益为主要目标。这种商业模式在游戏产业中已经成为一个独特而且颇具潜力的领域。然而&#xff0c;随之而来的是防封问题&#xff0c;特别是当游戏工作室试图通过多开账号来赚取更多收益时。因此&#xff0c;我们有…

【第6节】Lagent AgentLego 智能体应用搭建

目录 1 基础课程2 安装环境2.1 教程要求2.2 安装 Lagent 和 AgentLego 3 实践操作3.1 Lagent&#xff1a;轻量级智能体框架3.1.1 Lagent Web Demo 使用3.1.2 用 Lagent 自定义工具 3.2 AgentLego&#xff1a;组装智能体“乐高”3.2.1 AgentLego 直接使用部分3.2.2 AgentLego We…