当前位置: 首页 > news >正文

Python一分钟:装饰器

一、装饰器基础

函数即对象

在python中函数可以作为参数传递,和任何其它对象一样如:str、int、float、list等等

def say_hello(name):return f"Hello {name}"def be_awesome(name):return f"Yo {name}, together we're the awesomest!"def greet_bob(greeter_func):return greeter_func("Bob")

内部函数

在函数内部可以创建函数,这样的函数被称为内部函数:

def parent():print("Printing from parent()")def first_child():print("Printing from first_child()")def second_child():print("Printing from second_child()")second_child()first_child()

在python在交互式shell中运行:

python -i test.py

在使用 Python 时,尤其是在交互式 shell 中,其强大的自省(introspection)能力提供了极大的便利。自省是指对象在运行时能够了解自身属性的能力。

>>> parent()

内部函数只有在父函数被调用时才会被定义,它的作用域仅限于父函数parent()内:

>>> first_child()
Traceback (most recent call last):...
NameError: name 'first_child' is not defined

函数作为返回值

函数可以作为返回值返回:

def parent(num):def first_child():return "Hi, I'm Elias"def second_child():return "Call me Ester"if num == 1:return first_childelse:return second_child

通过变量保存返回的函数引用,可以像普通函数那样正常调用:

>>> first = parent(1)
>>> second = parent(2)>>> first
<function parent.<locals>.first_child at 0x7f599f1e2e18>>>> second
<function parent.<locals>.second_child at 0x7f599dad5268>

简单的装饰器

def decorator(func):def wrapper():print("Something is happening before the function is called.")func()print("Something is happening after the function is called.")return wrapperdef say_whee():print("Whee!")say_whee = decorator(say_whee)

在shell中运行:

>>> from hello_decorator import say_whee>>> say_whee()
# <function decorator.<locals>.wrapper at 0x7f3c5dfd42f0>

通过@符号来使用装饰器:

def decorator(func):def wrapper():print("Something is happening before the function is called.")func()print("Something is happening after the function is called.")return wrapper@decorator
def say_whee():print("Whee!")

传递参数:

def do_twice(func):def wrapper_do_twice(*args, **kwargs):func(*args, **kwargs)func(*args, **kwargs)return wrapper_do_twice

在shell中运行:

>>> from decorators import do_twice>>> @do_twice
... def return_greeting(name):
...     print("Creating greeting")
...     return f"Hi {name}"
...>>> return_greeting("Adam")
# Creating greeting
# Creating greeting
# 'Hi Adam'

保留原始信息

当函数被我们之前创建的装饰器装饰时,它的内部信息就会变得混乱,使用@functools.wraps装饰器可以解决这个问题:

import functoolsdef do_twice(func):@functools.wraps(func)def wrapper_do_twice(*args, **kwargs):func(*args, **kwargs)return func(*args, **kwargs)return wrapper_do_twice

在shell中运行:

>>> from decorators import do_twice>>> @do_twice
... def say_whee():
...     print("Whee!")
...>>> say_whee
<function say_whee at 0x7ff79a60f2f0>>>> say_whee.__name__
'say_whee'>>> help(say_whee)
Help on function say_whee in module whee:say_whee()

可以看到经过@functools.wraps装饰器后,say_whee函数的元数据被保留下来,包括函数名、文档字符串等。

二、更复杂的装饰器

嵌套装饰器

装饰器可以堆叠用于一个函数:

>>> from decorators import debug, do_twice>>> @debug
... @do_twice
... def greet(name):
...     print(f"Hello {name}")

带参数的装饰器

我们可以定义能够接收参数的装饰器,如下:

from decorators import repeat@repeat(num_times=4)
def greet(name):print(f"Hello {name}")greet("World")

实现方法如下:

import functools# ...def repeat(num_times):def decorator_repeat(func):@functools.wraps(func)def wrapper_repeat(*args, **kwargs):for _ in range(num_times):value = func(*args, **kwargs)return valuereturn wrapper_repeatreturn decorator_repeat

拆分讲解上面的代码:
首先decorator_repeat部分的行为,就和我们之前定义的普通装饰器一样:

...def decorator_repeat(func):@functools.wraps(func)def wrapper_repeat(*args, **kwargs):for _ in range(num_times):value = func(*args, **kwargs)return valuereturn wrapper_repeat
...

外层由repeat()函数接收参数,并返回wrapper_repeat装饰器的引用。

在装饰器中跟踪状态

可以实现装饰器对象中添加属性来追踪函数调用次数:

import functoolsdef count(func):@functools.wraps(func)def warp(*args, **kwargs):warp.num_calls += 1print(f"Call {warp.num_calls} of {func.__name__}()")return func(*args, **kwargs)warp.num_calls = 0return warp@count
def hello():print("Hello")hello()
hello()
hello()

类装饰器

有两种不同的方式可以在类中使用装饰器,第一种方法和我们上面学到的在函数中使用装饰器的方法非常类似。

Python有很多内置的装饰器很常用:

  • @classmethod
  • @staticmethod
  • @property

在python中维护状态的典型方法就是使用类。之前实现的count函数可以使用类装饰器重写。为了使实例可调用,需要实现.__call__()方法:

>>> class Counter:
...     def __init__(self, start=0):
...         self.count = start
...     def __call__(self):
...         self.count += 1
...         print(f"Current count is {self.count}")

每次调用实例都会执行.__call__()方法:

>>> counter = Counter()
>>> counter()
Current count is 1>>> counter()
Current count is 2>>> counter.count

实现装饰器类的典型方法是应该实现.__init__().__call__()

import functools# ...class CountCalls:def __init__(self, func):functools.update_wrapper(self, func)self.func = funcself.num_calls = 0def __call__(self, *args, **kwargs):self.num_calls += 1print(f"Call {self.num_calls} of {self.func.__name__}()")return self.func(*args, **kwargs)

使用方法:

>>> from decorators import CountCalls>>> @CountCalls
... def say_whee():
...     print("Whee!")
...>>> say_whee()
# Call 1 of say_whee()
# Whee!>>> say_whee()
# Call 2 of say_whee()
# Whee!>>> say_whee.num_calls
# 2

原文链接

相关文章:

Python一分钟:装饰器

一、装饰器基础 函数即对象 在python中函数可以作为参数传递&#xff0c;和任何其它对象一样如:str、int、float、list等等 def say_hello(name):return f"Hello {name}"def be_awesome(name):return f"Yo {name}, together were the awesomest!"def gr…...

Docker部署ddns-go教程(包含完整的配置过程)

本章教程教程,主要介绍如何用Docker部署ddns-go。 一、拉取容器 docker pull jeessy/ddns-go:v6.7.0二、运行容器 docker run -d \--name ddns-go \--restart unless-stopped \...

简单多状态dp第三弹 leetcode -买卖股票的最佳时机问题

309. 买卖股票的最佳时机含冷冻期 买卖股票的最佳时机含冷冻期 分析: 使用动态规划解决 状态表示: 由于有「买入」「可交易」「冷冻期」三个状态&#xff0c;因此我们可以选择用三个数组&#xff0c;其中&#xff1a; ▪ dp[i][0] 表示&#xff1a;第 i 天结束后&#xff0c…...

游戏化在电子课程中的作用:提高参与度和学习成果

游戏化&#xff0c;即游戏设计元素在非游戏环境中的应用&#xff0c;已成为电子学习领域的强大工具。通过将积分、徽章、排行榜和挑战等游戏机制整合到教育内容中&#xff0c;电子课程可以变得更具吸引力、激励性和有效性。以下是游戏化如何在转变电子学习中发挥重要作用&#…...

php+mysql安装

1.卸载mysql 没启动不停止 2.下载 3.解压 4.点击安装 5.出现成功 端口占用修改 修改端口89或者87 可视化扩展 修改后重启 开启扩展...

音视频入门基础:FLV专题(5)——FFmpeg源码中,判断某文件是否为FLV文件的实现

一、引言 通过FFmpeg命令&#xff1a; ./ffmpeg -i XXX.flv 可以判断出某个文件是否为FLV文件&#xff1a; 所以FFmpeg是怎样判断出某个文件是否为FLV文件呢&#xff1f;它内部其实是通过flv_probe函数来判断的。从《FFmpeg源码&#xff1a;av_probe_input_format3函数和AVI…...

Tomcat 乱码问题彻底解决

1. 终端乱码问题 找到 tomcat 安装目录下的 conf ---> logging.properties .修改ConsoleHandler.endcoding GBK &#xff08;如果在idea中设置了UTF-8字符集&#xff0c;这里就不需要修改&#xff09; 2. CMD命令窗口设置编码 参考&#xff1a;WIN10的cmd查看编码方式&am…...

RGB颜色模型

RGB颜色模型是一种广泛应用于数字图像和计算机图形领域的颜色表示方法 一、基本概念 RGB 代表红色&#xff08;Red&#xff09;、绿色&#xff08;Green&#xff09;和蓝色&#xff08;Blue&#xff09;三种基本颜色。这些颜色被视为加色模型中的原色&#xff0c;意味着它们可…...

智能工厂的软件设计 创新型原始制造商(“创新工厂“)的Creator原型(统一行为理论)之2

Q8、今天我们继续昨天开始的 “智能工厂的软件设计”以“统一行为理论”为指导原则的 创新型原始制造商的Creator伪代码--创新工厂“原型”。这是在前述将“程序program”问题的三个体现“方面”&#xff08;逻辑/语言/数学&#xff09; 视为符号学的三分支&#xff08;语用语义…...

【个人博客hexo版】hexo安装时会出现的一些问题

项目场景&#xff1a; 项目场景&#xff1a;在完成了GitHub仓库和git的连接之后&#xff0c;就要新建一个文件夹&#xff08;例如hexo blog&#xff09;进行下一步hexo的使用 问题描述 例如&#xff1a;如图所示 原因分析&#xff1a; 这些error不用看它到底是什么&#xf…...

道路裂缝,坑洼,病害数据集-包括无人机视角,摩托车视角,车辆视角覆盖道路

道路裂缝&#xff0c;坑洼&#xff0c;病害数据集 包括无人机视角&#xff0c;摩托车视角&#xff0c;车辆视角 覆盖道路所有问题 一共有八类16000张 1到7依次为: [横向裂缝, 纵向裂缝, 块状裂缝, 龟裂, 坑槽, 修补网状裂缝, 修补裂缝, 修补坑槽] 道路病害&#xff08;如裂缝、…...

java接口文档配置

接口文档配置 一. swagger与knife4j 配置 1. 导入依赖 <!--swagger接口文档说明--> <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId> </dependency> <dependency><groupId>…...

【服务器第二期】mobaxterm软件下载及连接

【服务器第二期】mobaxterm软件下载及连接 前言什么是SSH什么是FTP/SFTP mobaxterm软件介绍mobaxterm软件下载SSH登录使用方法1-新建ssh连接方法2-打开已有的ssh连接方法3-通过ssh命令建立连接 SFTP数据传输方法1-建立ssh连接后直接拖拽方法2-建立sftp连接再拖拽方法3-直接使用…...

排序-----计数排序(非比较排序)

原理&#xff1a; 存在的问题&#xff1a;数组空间浪费 所以要相对映射&#xff0c;不要绝对映射 calloc()函数的功能是:为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0. // 时间复杂度:O(Nrange) // 只适合整数/适合范围集中 // 空间范围度&#xff1a;…...

[Python]案例驱动最佳入门:Python数据可视化在气候研究中的应用

在全球气候问题日益受到关注的今天&#xff0c;气温变化成为了科学家、政府、公众讨论的热门话题。然而&#xff0c;全球气温究竟是如何变化的&#xff1f;我们能通过数据洞察到哪些趋势&#xff1f;本文将通过真实模拟的气温数据&#xff0c;结合Python数据分析和可视化技术&a…...

PyQt5 导入ui文件报错 AttributeError: type object ‘Qt‘ has no attribute

问题描述&#xff1a; 利用 PyQt5 编写可视化界面是较为普遍的做法&#xff0c;但是使用全新UI版本的 Pycharm 修改之前正常的UI文件时&#xff0c;在没有动其他代码的情况下发现出现以下报错 AttributeError: type object Qt has no attribute Qt::ContextMenuPolicy::Defaul…...

Unity中Rigidbody 刚体组件和Rigidbody类是什么?

Rigidbody 刚体组件 Rigidbody 是 Unity 中的一个组件&#xff0c;它可以让你的游戏对象像真实世界中的物体一样移动和碰撞。想象一下&#xff0c;你有一个小球&#xff0c;你希望它像真实世界中的球一样滚动、弹跳和碰撞&#xff0c;那么你就可以给这个小球添加一个 Rigidbod…...

MySQL学习笔记(持续更新中)

1、Mysql概述 1.1 数据库相关概念 三个概念&#xff1a;数据库、数据库管理系统、SQL 名称全称简称数据库存储数据的仓库&#xff0c;数据是有组织的进行存储DataBase&#xff08;DB&#xff09;数据库管理系统操纵和管理数据库的大型软件DataBase Mangement System&#xf…...

sqlserver插入数据删除数据

1、插入数据 1.1 直接插入 1.1.1 方式一 insert into test values(001,黎明,1),(002,冯绍峰,1),(003,菲菲,2);1.1.2 方式二 insert into test(ID,Name,Sex) values(004,丽丽,2),(005,凌晨,2),(006,虾米,1);1.2 插入部分行 insert into test(ID,Name) values(007,红)2、删除…...

[51单片机] 简单介绍 (一)

文章目录 1.单片机介绍2.单片机内部三大资源3.单片机最小系统4.STC89C52单片机 1.单片机介绍 兼容Intel的MCS-51体系架构的一系列单片机。 STC89C52&#xff1a;8K FLASH、512字节RAM、32个IO口、3个定时器、1个UART、8个中断源。 单片机简称MCU单片机内部集成了CPU、RAM、RO…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台

🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

渗透实战PortSwigger靶场:lab13存储型DOM XSS详解

进来是需要留言的&#xff0c;先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码&#xff0c;输入的<>当成字符串处理回显到页面中&#xff0c;看来只是把用户输…...

node.js的初步学习

那什么是node.js呢&#xff1f; 和JavaScript又是什么关系呢&#xff1f; node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说&#xff0c; 需要在node.js的环境上进行当JavaScript作为前端开发语言来说&#xff0c;需要在浏览器的环境上进行 Node.js 可…...

【QT控件】显示类控件

目录 一、Label 二、LCD Number 三、ProgressBar 四、Calendar Widget QT专栏&#xff1a;QT_uyeonashi的博客-CSDN博客 一、Label QLabel 可以用来显示文本和图片. 核心属性如下 代码示例: 显示不同格式的文本 1) 在界面上创建三个 QLabel 尺寸放大一些. objectName 分别…...