python第二十节闭包函数与装饰器

闭包函数与装饰器

  • 闭包函数
    • 闭包的构成条件
    • 闭包如何理解
  • 装饰器
    • 函数装饰器一
    • 函数装饰器二
    • 类装饰器一
    • 类装饰器二

闭包函数

闭包的构成条件

  • 在函数嵌套(函数里面再定义函数)的前提下
  • 内部函数使用了外部函数的变量(参数)
  • 外部函数的返回值是内部函数的引用

闭包如何理解

  • 一般来说,如果一个函数结束,函数内部的变量、参数会被释放掉;而闭包则不
    同,它在外部函数结束时,会把内部函数中用到的外部函数的变量、参数保存到内
    部函数的__closure__属性中,以提供给内部函数使用
def outer(a):b = 5def inner():c = 7print(a + b + c)return inner""" 这里的inner_func就是一个闭包, 本质上就是inner函数,
只不过还打包了它所依赖的参数a和变量b而已 """
inner_func = outer(3)""" 自定义函数都会有一个__closure__属性, 如果不是闭包函数, 则返回None
如果是则返回一个由cell对象组成的元组, 每个cell对象的cell_contents属性就是外部
函数保存的变量 """
print(inner_func.__closure__)
print(inner_func.__closure__[0].cell_contents) # 3 (外部函数保存的参数a的值)
print(inner_func.__closure__[1].cell_contents) # 5 (外部函数保存的变量b的值)
inner_func()

将实现特定的功能代码封装成装饰器,提高代码复用率
def outer():funcs = []for k in range(3):def inner():return k * kfuncs.append(inner)return funcs
""" 这里的f1, f2, f3都是闭包, 本质上都是inner函数, 且使用了outer函数的变量k
outer函数在结束时, 将变量k保存到内部函数的__closure__属性中, 而k最后为2 """
f1, f2, f3 = outer()
print(f1.__closure__[0].cell_contents)
print(f2.__closure__[0].cell_contents)
print(f3.__closure__[0].cell_contents)
print(f1())
print(f2())
print(f3())

装饰器

装饰器,顾名思义就是起装饰作用的,不改变原来函数作用的,只是在原来函数上增加些额
外的功能。

装饰器并不是编码必须性,不使用装饰器也完全可以,很多时候使用它是为了:

  • 使代码更加优雅,结构更加清晰
  • 将实现特定的功能代码封装成装饰器,提高代码复用率

函数装饰器一

import timedef timer(func):def wrapper(sleep_time):t1 = time.time()func(sleep_time)t2 = time.time()cost_time = t2 - t1print(f"花费时间:{cost_time}秒")return wrapper@timer # 这个装饰器就是函数
def function(sleep_time):
time.sleep(sleep_time)"""
执行顺序说明:
代码从上往下执行, 先导入time模块, 定义timer函数, 再执行到@timer装饰器,
该函数装饰器没有调用, 再定义function函数, 当被装饰的函数定义好了, 则将被
装饰的函数作为参数传入装饰器函数并执行, 即timer(function), 返回wrapper函数的
引用,
所以当最后执行function(3)时, 其实等价于wrapper(3), 而wrapper函数中又调用了
func函数,
即function函数 """
function(3)

函数装饰器二

import timedef interaction(name):def wrapper(func):def deco(work_time):# print("deco函数被调用")print(f"{name}, 你好, 请把要洗的衣物放进来!")func(work_time)print(f"{name}, 我帮你把衣物洗好了, 快来拿!")return decoreturn wrapper@interaction("张三")
def washer(work_time):
time.sleep(work_time)
print("嘀嘀嘀...")"""
执行顺序说明:
代码从上往下执行, 先导入time模块, 定义interaction函数, 再执行到@interaction
装饰器,
该函数装饰器被调用, 则执行该函数, 定义wrapper函数, 并返回其引用, 再定义washer
函数, 当
被装饰的函数定义好了, 则将被装饰的函数作为参数传入刚刚执行装饰器返回的wrapper函数
并执行,
即wrapper(washer), 再定义deco函数, 并返回其引用, 所以当最后执行washer(3)时,
其实等价于deco(3), 而deco函数中又调用了func函数, 即washer函数 """
washer(3)

类装饰器一

import timeclass Timer:def __init__(self, func):self.func = funcdef __call__(self, sleep_time):t1 = time.time()self.func(sleep_time)t2 = time.time()cost_time = t2 - t1print(f"花费时间:{cost_time}秒")@Timer # 这个装饰器就是类
def function(sleep_time):time.sleep(sleep_time)
"""
执行顺序说明:
代码从上往下执行, 先导入time模块, 定义Timer类和方法, 执行到@Timer装饰器时,
该类装饰器没有实例化, 再定义function函数, 当被装饰的函数定义好了, 则将被
装饰的函数作为参数传入类装饰器并实例化, 即Timer(function), 实例化调用初始化方
法,
创建实例变量, __new__返回实例对象, 当最后执行function(3)时, 其实等价于
Timer(function)(3),
即调用__call__方法, 而该方法中又调用了func函数, 即function函数 """
function(3)

类装饰器二

import time
class Interaction:def __init__(self, name):self.name = name
def __call__(self, func):def deco(work_time):print(f"{self.name}, 你好, 请把要洗的衣物放进来!")func(work_time)print(f"{self.name}, 我帮你把衣物洗好了, 快来拿!")return deco
@Interaction("张三")
def washer(work_time):time.sleep(work_time)print("嘀嘀嘀...")"""
执行顺序说明:
代码从上往下执行, 先导入time模块, 定义Interaction类和方法, 执行到
@Interaction装饰器时,
该类装饰器进行实例化, 调用初始化方法, 创建实例变量, __new__返回实例对象, 再定义
washer函数,
当被装饰的函数定义好了, 则将被装饰的函数作为参数调用实例对象, 即Interaction("张
三")(washer),
即调用__call__方法, 定义deco函数并返回其引用, 所以当最后执行washer(3)时, 其实
等价于deco(3), 而其中又调用了func函数, 即washer函数 """
washer(3)

内置装饰器

  • @classmethod
    • 将类中的方法装饰为类方法
  • @staticmethod
    • 将类中的方法装饰为静态方法
  • @property
    • 将类中的方法装饰为只读属性
class Student:def __init__(self, name, age):self.name = nameself.age = age@propertydef adult_age_p(self):return 18def adult_age(self):return 18@propertydef adult_flag(self):return self.age >= self.adult_age_pstu = Student("张三", 18)
print(stu.adult_age()) # 没有加@property, 必须使用正常的调用方法的形式,在后面加()
print(stu.adult_age_p) # 加了@property, 用调用属性的形式来调用方法, 后面不需要加()
print(stu.adult_flag) # True
stu.age = 17 # 可以修改stu对象的age属性
# stu.adult_age_p = 19 # 报错:@property将方法装饰为只读属性, 不能修改
print(stu.adult_flag) # False

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

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

相关文章

C++/Qt 元类型——枚举 序列化与反序列化

/*** brief 枚举转字符串* tparam T 枚举类型* param s 枚举类型变量* return 字符串*/ template <typename T> inline QString EnumToString(T s) {// T是枚举类型&#xff0c;编译判断static_assert(std::is_enum<T>::value, "T must be an enum type"…

Android logcat系统

一 .logcat命令介绍 android log系统: logcat介绍 : logcat是android中的一个命令行工具&#xff0c;可以用于得到程序的log信息. 二.C/Clogcat访问接口 Android系统中的C/C日志接口是通过宏来使用的。在system/core/include/android/log.h定义了日志的级别&#xff1a; /…

mysql binlog禁用

要禁用 MySQL 的二进制日志&#xff08;binlog&#xff09;&#xff0c;你可以通过以下步骤进行操作&#xff1a; 临时禁用&#xff1a; 如果你只是想临时禁用二进制日志&#xff0c;你可以使用以下 SQL 命令&#xff1a; sql SET sql_log_bin 0; 这只会影响当前的会话。当…

Linkedln领英账号限制问题|通过代理IP安全使用Linkedln

LinkedIn是跨境外贸必备的拓客工具&#xff0c;世界各地的许多专业人士都使用领英来作为发布和共享内容的主要工具&#xff0c;这使得它成为跨境出海必备的渠道工具。 但是不少做外贸的朋友都知道&#xff0c;领英账号很容易遭遇限制封禁&#xff0c;但如果善用工具&#xff0…

【数据集】ENSO-基于NOAA发布ONI值

NOAA-ONI&#xff08;Oceanic Nino Index&#xff09; ENSO划分标准&#xff1a; 当某ENSO年的指数值连续6个月大于0.5 ℃时&#xff0c;将该年归类为El Nio年当低于-0.5℃时&#xff0c;将其归类为La Nia年否则&#xff0c;年份为中性。 数据下载 注意&#xff1a;此页面将…

改造muduo,不依赖boost,用C++11重构

组件的实现 1. 序 1.1. 总述 muduo库是基于多Reactor-多线程模型实现的TCP网络编程库&#xff0c;性能良好。如libev作者&#xff1a;“One loop per thread is usually a good model”&#xff0c;muduo库的作者陈硕在其《Linux多线程服务端编程》中也力荐这种“One loop pe…

每日五道java面试题之mysql数据库篇(四)

目录&#xff1a; 第一题&#xff1a; Hash索引和B树所有有什么区别或者说优劣呢?第二题&#xff1a;数据库为什么使用B树而不是B树&#xff1f;第三题&#xff1a;B树在满足聚簇索引和覆盖索引的时候不需要回表查询数据&#xff1f;第四题&#xff1a;什么是聚簇索引&#xf…

Java解决比特位计数

Java解决比特位计数 01 题目 给定一个非负整数 n &#xff0c;请计算 0 到 n 之间的每个数字的二进制表示中 1 的个数&#xff0c;并输出一个数组。 示例 1: 输入: n 2 输出: [0,1,1] 解释: 0 --> 0 1 --> 1 2 --> 10示例 2: 输入: n 5 输出: [0,1,1,2,1,2] 解释:…

redis缓存注解使用

这里写自定义目录标题 一、引入依赖二、修改启动类和配置文件三、添加配置类四、缓存示例 一、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><optional>tru…

浅谈WPF之Binding数据校验和类型转换

在WPF开发中&#xff0c;Binding实现了数据在Source和Target之间的传递和流通&#xff0c;就像现实生活中的一条条道路&#xff0c;建立起了城镇与城镇之间的衔接&#xff0c;而数据校验和类型转换&#xff0c;就像高速公路之间的收费站和安检站。那在WPF开发中&#xff0c;如何…

在 java 中 arraylist 与 linkedlist 的区别

ArrayList和LinkedList都是Java中的类&#xff0c;它们都实现了List接口&#xff0c;但是它们在实现方式和性能上有一些重要的区别。 底层实现&#xff1a; ArrayList 是基于动态数组的实现&#xff0c;它的元素在内存中是连续存储的。LinkedList 是双向链表的实现&#xff0c;…

Redis核心数据结构之SDS(一)

数据结构与对象 简单动态字符串 概述 Redis没有直接使用C语言传统的字符串表示(以空字符结尾的字符数组&#xff0c;简称C字符串)&#xff0c;而是自己构建了一种名为简单动态字符串(Simple Dynamic String, SDS)的后向类型&#xff0c;并将SDS用作Redis的默认字符串表示。在…

数据库学习案例20240304-mysql数据库案例总结(碎片,统计信息)

1 表中的碎片 在InnoDB中删除行的时候&#xff0c;这些行只是被标记为“已删除”&#xff0c;而不是真正从物理存储上进行了删除&#xff0c;因而存储空间也没有真正被释放回收。InnoDB的Purge线程会异步地来清理这些没用的索引键和行。但是依然没有把这些释放出来的空间还给操…

基于SSM的农业电商服务系统(农产品销售管理系统)(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的农业电商服务系统&#xff08;农产品销售管理系统&#xff09;&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#…

五、软考-系统架构设计师笔记-信息安全技术基础知识

信息安全技术基础知识 1、信息安全基础知识概述 信息安全的概念 信息安全包括 5 个基本要素&#xff1a; 机密性:确保信息不暴露给未授权的实体或进程。完整性:只有得到允许的人才能修改数据&#xff0c;并且能够判别出数据是否已被篡改。可用性:得到授权的实体在需要时可以…

SpringBoot源码解读与原理分析(四十)基于jar/war包的运行机制

文章目录 前言第14章 运行SpringBoot应用14.1 部署打包的两种方式14.1.1 以可独立运行jar包的方式14.1.2 以war包的方式 14.2 基于jar包的独立运行机制14.2.1 可独立运行jar包的相关知识14.2.2 SpringBoot的可独立运行jar包结构14.2.3 JarLauncher的设计及工作原理14.2.3.1 Jar…

06、MongoDB -- MongoDB 基本用法(删除文档、查询文档、查询运算符)

目录 MongoDB 基本用法演示前提&#xff1a;登录单机模式的 mongodb 服务器命令登录【admin】数据库的 mongodb 客户端命令登录【test】数据库的 mongodb 客户端命令 删除文档语法格式两个变体版本&#xff1a;1、remove&#xff1a;根据【name】字段删除一条文档2、deleteOne&…

代码工具APEX的入门使用(未包含安装)

第一次使用APEX是2019年&#xff0c;这个技术成名已久只是我了解的比较晚。请看Oracle ACE的网站&#xff0c;这就是用APEX做的。实际上有一次我看O记的人操作他们的办公流程&#xff0c;都是用APEX做的。 那一年&#xff0c;我用APEX做了一个CMDB的管理系统。那时候还没有流行…

从0搭建Azure DevOps Server

Windows虚拟机搭建DevOps 服务器 背景资源准备安装软件需求流程版本兼容性安装SQL ServerSSMS安装visual StudioAzure DevOps Server测试本地访问端口更改及外界访问 背景 搭建一台Azure DevOps Server 供我们运维项目开发&#xff0c;现在DevOps运维已成为一个主流&#xff0…

C向C++的一个过渡

思维导图 输入输出&#xff0c;以及基础头文件 在c语言中我们常用scanf("%d",&n);和printf("%d\n",n);来输出一些变量和常量&#xff0c;在C中我们可以用cin;和cout;来表示输入输出。 在C语言中输入输出有头文件&#xff0c;在C也有头文件&#xff0…