python打卡day27

函数装饰器

知识点回顾:

  1. 装饰器的思想:进一步复用
  2. 函数的装饰器写法
  3. 注意内部函数的返回值

日常ctrl点进某个复杂的项目,发现函数定义上方有一个@xxx,它就是装饰器。装饰器本质上是一个 Python 函数,可以在不修改原函数代码的情况下,给函数添加额外功能。本质是如果让一个函数具备太多功能,那么他看起来就会比较乱,可读性比较差,如果把其中一部分相同甚至可以复用的功能用一个新的函数来调用,然后让2个函数同时实现,就会做到:

  • 进一步封装了函数的一些用法,做到dry原则(don't repeat yourself)
  • 使函数更加具有可读性

所以装饰器本身就是函数中调用其他函数,实现先拆分函数,再合并函数的功能

举个例子,假设你有一个函数 prime_nums() ,核心功能是筛选2-10000的质数并输出:

def is_prime(num):if num < 2:return Falseelif num == 2:return Trueelse:for i in range(2, num):if num % i == 0:return Falsereturn Truedef prime_nums():for i in range(2, 10000):if is_prime(i):print(i)prime_nums()

现在要加入计算耗时的功能,一般会这样做:

import time
def is_prime(num):if num < 2:return Falseelif num == 2:return Trueelse:for i in range(2, num):if num % i == 0:return Falsereturn Truedef prime_nums():t1 = time.time()for i in range(2, 10000):if is_prime(i):print(i)t2 = time.time()print(f"执行时间:{t2 - t1}秒")prime_nums()

但如果使用函数装饰器:

# 定义一个装饰器
def display_time(func): # 装饰器函数,接收一个函数func作为参数def wrapper(): # 定义一个内部函数,在装饰器中wrapper函数是一个常用的函数名,并非强制,约定俗成的t1 = time.time()func()  # 直接调用原函数(无参数),这里的func()是指装饰器需要修饰的函数,在这里是prime_nums()t2 = time.time()print(f"执行时间: {t2 - t1} 秒")return wrapper # return wrapper是返回函数对象,如果是return wrapper()则是立即执行wrapper函数def is_prime(num):if num < 2:return Falseelif num == 2:return Trueelse:for i in range(2, num):if num % i == 0:return Falsereturn True@display_time # 相当于 prime_nums = display_time(prime_nums)
def prime_nums():for i in range(2, 10000):if is_prime(i):print(i)prime_nums()

装饰函数就是在原函数的基础上套了个壳子wrapper() ,这个壳子里不仅有原函数,还有额外功能的函数实现:

✅ 外层的装饰器display_time函数:确实只是"取名+接收原函数"的入口

✅ wrapper函数:真正的"功能增强实现层",不可或缺

如果原函数需要传入参数并且还要有返回值(比如传入参数maxnum,计算2-maxnum的质数的个数),那么定义装饰器函数的时候也要传入参数和传递返回值:

def display_time(func):def wrapper(*args, **kwargs):  # 接收任意参数start = time.time()result = func(*args, **kwargs)  # 执行原函数并保存返回值end = time.time()print(f"耗时: {end-start}秒")return result  # 返回原函数的结果return wrapper

这里提一下两个返回 return result 和 return wrapper :

  • return wrapper 属于外层display_time函数,在装饰器被应用时执行,返回包装后的函数对象
  • return result 属于内层wrapper函数,在被装饰的原函数每次调用时执行,返回原函数的计算结果

作业

编写一个装饰器 logger,在函数执行前后打印日志信息(如函数名、参数、返回值)

def logger(func):def wrapper(*args, **kwargs):print(f'执行函数:{func.__name__},参数为:{args},{kwargs}') # {}内不能使用解包操作符*result = func(*args, **kwargs)print(f'函数已执行,返回结果:{result}')return resultreturn wrapper@logger
def calculate_average(*args, **kwargs):if not args:return 0try:average = sum(args) / len(args) # 这里不用*是因为元组本身就是这两个函数的可迭代对象,# 比如sum((1,2,3))合法,但sum(1,2,3)不行,因为sum()只接受一个可迭代参数return averageexcept TypeError:print("错误:所有参数必须是数字")return 0print(f'[4, 8, 6.5, 15]的均值为:{calculate_average(4, 8, 6.5, 15)}')
print(f'空输入的均值为:{calculate_average()}')
print(f'非数字输入的均值为:{calculate_average("a", "b")}')
执行函数:calculate_average,参数为:(4, 8, 6.5, 15),{}
函数已执行,返回结果:8.375
[4, 8, 6.5, 15]的均值为:8.375
执行函数:calculate_average,参数为:(),{}
函数已执行,返回结果:0
空输入的均值为:0
执行函数:calculate_average,参数为:('a', 'b'),{}
错误:所有参数必须是数字
函数已执行,返回结果:0
非数字输入的均值为:0

收获心得:

函数装饰器真的是第一次接触,新奇

今天终于把昨天讲的 *args 和 **kwargs 这种什么时候解包(加上*)什么时候不解包(不加*)搞清楚了,只在需要将元组或字典拆分为独立参数时才使用*args或**kwargs,其他情况直接使用元组或字典即可

@浙大疏锦行

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

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

相关文章

【python基础知识】Day 27 函数专题2:装饰器

知识点&#xff1a; 装饰器的思想&#xff1a;进一步复用函数的装饰器写法注意内部函数的返回值 装饰器教程 作业&#xff1a; 编写一个装饰器 logger&#xff0c;在函数执行前后打印日志信息&#xff08;如函数名、参数、返回值&#xff09; def logger(func):def wrapper(*ar…

15 C 语言字符类型详解:转义字符、格式化输出、字符类型本质、ASCII 码编程实战、最值宏汇总

1 字符类型概述 在 C 语言中&#xff0c;字符类型 char 用于表示单个字符&#xff0c;例如一个数字、一个字母或一个符号。 char 类型的字面量是用单引号括起来的单个字符&#xff0c;例如 A、5 或 #。 当需要表示多个字符组成的序列时&#xff0c;就涉及到了字符串。在 C 语言…

Word图片格式调整与转换工具

软件介绍 本文介绍的这款工具主要用于辅助Word文档处理。 图片排版功能 经常和Word打交道的人或许都有这样的困扰&#xff1a;插入的图片大小各异&#xff0c;排列也参差不齐。若不加以调整&#xff0c;遇到要求严格的领导&#xff0c;可能会让人颇为头疼。 而这款工具能够统…

旧 docker 版本通过 nvkind 搭建虚拟多节点 gpu 集群的坑

踩坑 参考nvkind教程安装到Setup这一步&#xff0c;由于docker版本较旧&#xff0c;–cdi.enabled 和 config 参数执行不了 手动修改 /etc/docker/daemon.json 配置文件 "features": {"cdi": true}手动修改 /etc/nvidia-container-runtime/config.toml 配…

【python基础知识】Day26 函数

一、函数的定义 函数是一段具有特定功能的、可重用的语句组&#xff0c;用函数名来表示。在需要使用函数时&#xff0c;通过函数名进行调用。函数也可以看作一段具有名字的子程序&#xff0c;可以在需要使用它的地方进行调用执行&#xff0c;不需要在每个执行的地方重复编写这些…

Linux云计算训练营笔记day08(MySQL数据库)

Linux云计算训练营笔记day08&#xff08;MySQL数据库&#xff09; 目录 Linux云计算训练营笔记day08&#xff08;MySQL数据库&#xff09;数据准备修改更新update删除delete数据类型1.整数类型2.浮点数类型(小数)3.字符类型4.日期5.枚举: 表头的值必须在列举的值里选择拷贝表复…

浪潮云边协同:赋能云计算变革的强力引擎

在数字化浪潮以排山倒海之势席卷全球的当下&#xff0c;第五届数字中国建设峰会在福州盛大开幕。这场以“创新驱动新变革&#xff0c;数字引领新格局”为主题的行业盛会&#xff0c;宛如一座汇聚智慧与力量的灯塔&#xff0c;吸引了国内外众多行业精英齐聚一堂&#xff0c;共同…

【Ubuntu】安装BitComet种子下载器

环境 Ubuntu 24.04.2 下载依赖库 环境比较新&#xff0c;此软件需要依赖很多旧的库&#xff0c;逐个安装下载&#xff1a; 1.libicu70 http://nz.archive.ubuntu.com/ubuntu/pool/main/i/icu/libicu70_70.1-2_amd64.deb2.libjavascriptcoregtk-4.0-18 http://security.ubu…

编译OpenSSL时报错,Can‘t locate IPC/Cmd.pm in @INC perl环境

Unix / Linux / macOS $ ./Configure $ make $ make test1、make Can‘t locate IPC/Cmd.pm in INC [ Downloads ] - /source/index.html https://www.openssl.org/source/ yum -y install perl-IPC-Cmd 2.make test Can’t locate Test/More.pm in INC perl环境 yum -…

MySQL——九、锁

分类 全局锁表级锁行级锁 全局锁 做全库的逻辑备份 flush tables with read lock; unlock tables;在InnoDB引擎中&#xff0c;我们可以在备份时加上参数–single-transaction参数来完成不加锁的一致性数据备份 mysqldump --single-transaction -uroot -p123456 itcast>…

网络基础概念

目录 协议分层 OSI七层模型 TCP/IP五层模型 MAC地址 IP地址 IP地址和MAC地址的区别 端口号 端口号范围划分 理解套接字socket UDP协议概念 TCP协议概念 网络字节序 协议分层 协议本质上也是一种软件。在设计时&#xff0c;为了更好地实现模块化和解耦合&#xf…

CSS Grid布局:从入门到实战

CSS Grid布局&#xff1a;从入门到实战 一、初识Grid布局 还在为网页布局发愁吗&#xff1f;Flexbox虽然好用&#xff0c;但当遇到复杂布局时&#xff0c;CSS Grid才是真正的王者。Grid布局是CSS中最强大的二维布局系统&#xff0c;它就像一张无形的网格纸&#xff0c;让我们…