Python进阶:闭包、装饰器浅析,一对表兄弟

news/2024/4/27 0:51:26/文章来源:https://blog.csdn.net/u012951679/article/details/130232253

函数参数

函数名的意义

先上代码

def func_1():print("这是个很厉害的函数")print(func_1)

执行结果如下:

<function func_1 at 0x0000016E97A0B1C0>

可以看出函数名代表的就是函数内容在内存中的地址。

函数名():如func_1(),即表示执行函数名func_1所在地址中存储的代码。 

函数作为参数

def func_1():print("这是个很厉害的函数")def test_func_param(func):func()test_func_param(func_1)

上诉代码将func_1作为参数传递给test_func_param,传递的为func_1函数的地址,因此方法test_func_param中的func()执行的即为func_1函数。

闭包

闭包的作用

闭包可以保存函数中的变量,使其不会随着函数的调用结束而销毁。

闭包的定义

在函数嵌套的前提下,内部函数使用了外部函数的变量,外部函数又返回了内部函数。则这个使用了外部函数变量的内部函数就叫闭包。

由上述可得闭包形成的三个条件

  1. 函数嵌套
  2. 内部函数使用了外部函数的变量
  3. 外部函数返回了内部函数

代码如下:

# 1.定义一个外部函数嵌套一个内部函数
def outer(num1):# 2.嵌套的内部函数,并且在内部函数中访问了外部函数变量def inner(num2):num = num2 + num1print(f"执行结果:{num}")# 3.外部函数返回了内部函数return innerf = outer(10)
f(10)

执行结果为:

执行结果:20

闭包内修改外部变量

正常情况下直接修改外部变量的值是不起作用的。如下:

# 1.定义一个外部函数嵌套一个内部函数
def outer(num1):# 2.嵌套的内部函数,并且在内部函数中访问了外部函数变量def inner(num2):num1 = num2 + 10# 3.外部函数返回了内部函数,返回的函数即为闭包print(num1)inner(10)print(num1)return innerouter(10)

执行结果为:

10
10

 这说明对于外部变量num1的修改并没有起作用,这时候nonlocal就登场了。nonlocal的使用方式极其简单,有点类似global,如下:

# 1.定义一个外部函数嵌套一个内部函数
def outer(num1):# 2.嵌套的内部函数,并且在内部函数中访问了外部函数变量def inner(num2):nonlocal num1num1 = num2 + 10# 3.外部函数返回了内部函数,返回的函数即为闭包print(num1)inner(10)print(num1)return innerouter(10)

执行结果为:

10
20

装饰器

作用

在不改变函数源代码的情况下给函数增加相应的功能,装饰器的本质就是闭包。

原始使用

# 使用闭包实现装饰器功能
def check(fn):def inner():print("实名登录")fn()return inner# 原始方法
def comment():print("你相信光嘛?")# 使用装饰器重新装饰comment方法
comment = check(comment)
comment()

这样既可实现在不改变comment函数源代码的情况下给comment函数增加部分功能。

语法糖写法

# 使用闭包实现装饰器功能
def check(fn):def inner():print("实名登录")fn()return inner# 语法糖
@check
def comment():print("你相信光嘛?")# 使用装饰器装饰后的方法
comment()

两者效果一样,可以看出@check做的事情其实就是comment = check(comment),语法糖的原理是不是瞬间明了了。

以上代码能看出装饰器的本质就是将函数作为参数传递给闭包中的外部函数,同时在内部函数使用该函数,并且添加对应功能。

装饰带有参数的函数

# 使用闭包实现装饰器功能
def check(fn):def inner(a, b):print("数据校验")fn(a, b)return inner# 语法糖
@check
def add(a, b):print(f"求和为:{(a + b)}")# 使用装饰器装饰后方法
add(1, 2)

装饰带有返回值的函数

# 使用闭包实现装饰器功能
def check(fn):def inner(a, b):print("数据校验")return fn(a, b)return inner# 语法糖
@check
def add(a, b):return a + b# 使用装饰器装饰后的方法
print(add(1, 2))

执行结果如下

数据校验
3

 装饰不定长参数函数

# 使用闭包实现装饰器功能
def check(fn):def inner(*args, **kwargs):print("数据打印")fn(args, kwargs)return inner# 语法糖
@check
def scan(*args, **kwargs):print(args, kwargs)# 使用装饰器装饰后的方法
scan(1, 2, love = "China")

多个装饰器装饰一个方法

# 使用闭包实现装饰器1功能
def check1(fn):def inner():print("登录")fn()return inner# 装饰器2
def check2(fn):def inner():print("实名")fn()return inner# 语法糖
@check1
@check2
def comment():print("发表评论")# 使用装饰器装饰后的方法
comment()

执行结果

登录
实名
发表评论

 带参数的装饰器

注意这里是给装饰器加参数,上面那个是指给主要装饰的函数加参数,两者完全不同,那么怎么给装饰器加参数呐?首先明白亮点

  1. 装饰器的外部函数只能接受一个参数,那就是被装饰的函数,也就是之前代码中的fn参数
  2. 既然不能给装饰器外部函数添加第二个参数,那么就可以考虑再外部函数之外再加一个函数也就是套娃。

代码如下:

def param_test(check_data):# 使用闭包实现装饰器功能def check(fn):def inner():if check_data == "true":print("登录")fn()return innerreturn check# 语法糖
@param_test('true')
def comment():print("发表评论")# 使用装饰器装饰后的方法
comment()

如上,check为原本的装饰器函数,在外部在套一层函数实现将参数check_data传递给装饰器的作用,执行结果如下,毫无问题。

登录
发表评论

 类装饰器

__call__方法:一个类一旦实现了__call__方法,那么这个类的实例对象就可以像方法那样调用,调用的结果即为__call__方法的执行结果,如下:

class Check():def __call__(self, *args, **kwargs):print("call的使用")c = Check()
c()

执行结果为:

call的使用

c即为Check类的实例,c()执行的即为__call__方法的内容。 

类装饰器如下:

# 类装饰器
class Check:def __init__(self, fn):self.__fn = fn# call方法实现def __call__(self, *args, **kwargs):print("登录")self.__fn()# 相当于 comment = Check(comment)
@Check 
def comment():print("评论")comment()

其中@Check相当于comment = Check(comment),不清楚要掉头回去看看装饰器第一段代码了,Check(comment)初始化了类并传入comment对象,执行结束后comment即为类的实例,在执行comment()则触发call方法。

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

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

相关文章

模板方法设计模式解读

目录 豆浆制作问题 模板方法模式基本介绍 基本介绍 模板方法模式的原理类图 模板方法模式解决豆浆制作问题 应用实例要求 思路分析和图解(类图) 模板方法模式的钩子方法 模板方法模式的注意事项和细节 豆浆制作问题 编写制作豆浆的程序&#xff0c;说明如下: 1) 制作豆…

【LeetCode】剑指 Offer 67. 把字符串转换成整数 p318 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/ba-zi-fu-chuan-zhuan-huan-cheng-zheng-shu-lcof/ 1. 题目介绍&#xff08;67. 把字符串转换成整数&#xff09; 写一个函数 StrToInt&#xff0c;实现把字符串转换成整数这个功能。不能使用 atoi 或者其他类似的库函数。 …

研究生考试 之 计算机网络第七版(谢希仁) 第一章 课后答案

研究生考试 之 计算机网络第七版(谢希仁) 第一章 课后答案 目录 研究生考试 之 计算机网络第七版(谢希仁) 第一章 课后答案 一、简单介绍 二、计算机网络第七版(谢希仁) 第一章 课后答案 1、 计算机网络向用户可以提供哪些服务&#xff1f; 2、 试简述分组交换的要点。 3…

Kali下部署-Nessus漏扫工具

Nessus 是全世界最多人使用的系统漏洞扫描与分析软件。总共有超过75,000个机构使用Nessus 作为扫描该机构电脑系统的软件。 特点&#xff1a; 1、提供完整的电脑漏洞扫描服务&#xff0c;并随时更新漏洞库。 2、可以在本机或者是远端上进行遥控&#xff0c;进行系统的漏洞扫…

常见的四种排名函数的用法(sql)

四个排名函数&#xff1a; 1.row_number 2.rank 3.dense_rank 4.ntile 1. ROW_NUMBER&#xff08;排名场景推荐&#xff09; 1.1 介绍 在 SQL 中&#xff0c;ROW_NUMBER() 是一个窗口函数&#xff0c;它为结果集中的每一行分配一个唯一的序号。该函数的语法如下&#xff1a; …

JavaSE-part1

文章目录 Day01 面向对象特性1.java继承注意点2.多态2.1多态概述2.2多态中成员的特点:star::star:2.3多态的转型:star::star: 3.Super4.方法重写:star::star:5.Object类:star::star: Day02 面向对象特性1.代码块:star:(主要是初始化变量&#xff0c;先于构造器)2.单例设计模式:…

【移动端网页布局】移动端网页布局基础概念 ⑦ ( 在 PhotoShop 中使用 Cutterman 切二倍图 | 使用二倍图作为背景图像 )

文章目录 一、在 PhotoShop 中使用 Cutterman 切二倍图二、使用二倍图作为背景图像 一、在 PhotoShop 中使用 Cutterman 切二倍图 参考 【CSS】PhotoShop 切图 ③ ( PhotoShop 切图插件 - Cutterman | 下载、安装、启动、注册、登录 Cutterman - 切图神奇 插件 | 使用插件进行切…

3自由度并联绘图机器人实现写字功能(一)

1. 功能说明 本文示例将实现R305样机3自由度并联绘图机器人写字的功能。 2. 电子硬件 在这个示例中&#xff0c;采用了以下硬件&#xff0c;请大家参考&#xff1a; 主控板 Basra主控板&#xff08;兼容Arduino Uno&#xff09; 扩展板Bigfish2.1扩展板电池7.4V锂电池 3. 功能…

远程访问及控制ssh

SSH远程管理 OpenSSH服务器 SSH(Secure Shell) 协议 是一种安全通道协议。主要用来实现字符界面的远程登录、远程复制等功能。对通信数据进行了加密处理&#xff0c;用于远程管理其中包括用户登录时输入的用户口令。因此SSH协议具有很好的安全性------------&#xff08;同样…

d2l Transformer

终于到变形金刚了&#xff0c;他的主要特征在于多头自注意力的使用&#xff0c;以及摒弃了rnn的操作。 目录 1.原理 2.多头注意力 3.逐位前馈网络FFN 4.层归一化 5.残差连接 6.Encoder 7.Decoder 8.训练 9.预测 1.原理 主要贡献&#xff1a;1.纯使用attention的Enco…

Android程序员向音视频进阶,有前景吗

随着移动互联网的普及和发展&#xff0c;Android开发成为了很多人的就业选择&#xff0c;希望在这个行业能获得自己的一席之地。然而&#xff0c;随着时间的推移&#xff0c;越来越多的人进入到了Android开发行业&#xff0c;就导致目前Android开发的工作越来越难找&#xff0c…

EFI Driver Model(下)-USB 驱动设计

1、USB简介 通用串行总线&#xff08;英语&#xff1a;Universal Serial Bus&#xff0c;缩写&#xff1a;USB&#xff09;是一种串口总线标准&#xff0c;也是一种输入输出接口的技术规范&#xff0c;被广泛地应用于个人电脑和移动设备等信息通讯产品&#xff0c;并扩展至摄影…

我看谁没看过

vue在新窗口打开页面方法 const { href } this.$router.resolve({path: "/officePlatform/addPrompt"});window.open(href, "_blank"); 添加圆形标志 h3::before {content: "";display: inline-block;width: 13px;height: 13px;background: va…

NFT介绍及监管规则

什么是NFT NFT是Non-Fungible Token&#xff08;非同质化代币&#xff09;的缩写。 NFT是“Non-Fungible Token”的缩写&#xff0c;即非同质化代币。不同于FT&#xff08;Fungible Token&#xff0c;同质化代币&#xff09;&#xff0c;每一个NFT都是独一无二且不可相互替代的…

第二章 Maven 核心程序解压和配置

第一节 Maven核心程序解压与配置 1、Maven 官网地址 首页&#xff1a; Maven – Welcome to Apache Maven(opens new window) 下载页面&#xff1a; Maven – Download Apache Maven(opens new window) 下载链接&#xff1a; 具体下载地址&#xff1a;https://dlcdn.apac…

【云原生】Java 应用程序在 Kubernetes 上棘手的内存管理

文章目录 引言JVM 内存模型简介非 Heap 内存Heap 堆内存Kubernetes 内存管理JVM 和 Kubernetes场景 1 — Java Out Of Memory 错误场景 2 — Pod 超出内存 limit 限制场景 3 — Pod 超出节点的可用内存场景 4 — 参数配置良好&#xff0c;应用程序运行良好 结语 引言 如何结合…

三月、四月总计面试碰壁15次,作为一个27岁的测试工程师.....

3年测试经验原来什么都不是&#xff0c;只是给你的简历上画了一笔&#xff0c;一直觉得经验多&#xff0c;无论在哪都能找到满意的工作&#xff0c;但是现实却是给我打了一个大巴掌&#xff01;事后也不会给糖的那种... 先说一下自己的个人情况&#xff0c;普通二本计算机专业…

JVM调优最佳参数

项目背景 C端的项目&#xff0c;用户量比较多&#xff0c;请求比较多。 启动参数表 Xmx指定应用程序可用的最大堆大小。 Xms指定应用程序可用的最小堆大小。 &#xff08;一般情况下&#xff0c;需要设置Xmx和Xms为相等的值&#xff0c;且为一个固定的值&#xff09; 如果该值…

图像处理:均值滤波算法

目录 前言 概念介绍 基本原理 Opencv实现中值滤波 Python手写实现均值滤波 参考文章 前言 在此之前&#xff0c;我曾在此篇中推导过图像处理&#xff1a;推导五种滤波算法&#xff08;均值、中值、高斯、双边、引导&#xff09;。这在此基础上&#xff0c;我想更深入地研…

使用状态机实现幂等性

文章目录 背景幂等概念适用场景示例代码上述代码状态流转 背景 在某些场景下&#xff0c;可以使用状态机来实现幂等性。将业务流程抽象为一个状态机&#xff0c;定义各个状态之间的转换规则。当收到一个请求时&#xff0c;根据当前状态和请求类型来判断是否允许执行操作&#x…