python进阶装饰器_老生常谈Python进阶之装饰器

函数也是对象

要理解Python装饰器,首先要明白在Python中,函数也是一种对象,因此可以把定义函数时的函数名看作是函数对象的一个引用。既然是引用,因此可以将函数赋值给一个变量,也可以把函数作为一个参数传递或返回。同时,函数体中也可以再定义函数。

装饰器本质

可以通过编写一个纯函数的例子来还原装饰器所要做的事。

def decorator(func):

def wrap():

print("Doing someting before executing func()")

func()

print("Doing someting after executing func()")

return wrap

def fun_test():

print("func")

fun_test = decorator(fun_test)

fun_test()

# Output:

# Doing someting before executing func()

# func

# Doing someting after executing func()

fun_test所指向的函数的引用传递给decorator()函数

decorator()函数中定义了wrap()子函数,这个子函数会调用通过func引用传递进来的fun_test()函数,并在调用函数的前后做了一些其他的事情

decorator()函数返回内部定义的wrap()函数引用

fun_test接收decorator()返回的函数引用,从而指向了一个新的函数对象

通过fun_test()调用新的函数执行wrap()函数的功能,从而完成了对fun_test()函数的前后装饰

Python中使用装饰器

在Python中可以通过@符号来方便的使用装饰器功能。

def decorator(func):

def wrap():

print("Doing someting before executing func()")

func()

print("Doing someting after executing func()")

return wrap

@decorator

def fun_test():

print("func")

fun_test()

# Output:

# Doing someting before executing func()

# func

# Doing someting after executing func()

装饰的功能已经实现了,但是此时执行:

print(fun_test.__name__)

# Output:

# wrap

fun_test.__name__已经变成了wrap,这是应为wrap()函数已经重写了我们函数的名字和注释文档。此时可以通过functools.wraps来解决这个问题。wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

更规范的写法:

from functools import wraps

def decorator(func):

@wraps(func)

def wrap():

print("Doing someting before executing func()")

func()

print("Doing someting after executing func()")

return wrap

@decorator

def fun_test():

print("func")

fun_test()

print(fun_test.__name__)

# Output:

# Doing someting before executing func()

# func

# Doing someting after executing func()

# fun_test

带参数的装饰器

通过返回一个包裹函数的函数,可以模仿wraps装饰器,构造出一个带参数的装饰器。

from functools import wraps

def loginfo(info='info1'):

def loginfo_decorator(func):

@wraps(func)

def wrap_func(*args, **kwargs):

print(func.__name__ + ' was called')

print('info: %s' % info)

return func(*args, **kwargs)

return wrap_func

return loginfo_decorator

@loginfo()

def func1():

pass

func1()

# Output:

# func1 was called

# info: info1

@loginfo(info='info2')

def func2():

pass

func2()

# Output:

# func2 was called

# info: info2

装饰器类

通过编写类的方法也可以实现装饰器,并让装饰器具备继承等面向对象中更实用的特性

首先编写一个装饰器基类:

from functools import wraps

class loginfo:

def __init__(self, info='info1'):

self.info = info

def __call__(self, func):

@wrap

def wrap_func(*args, **kwargs):

print(func.__name__ + ' was called')

print('info: %s' % self.info)

self.after() # 调用after方法,可以在子类中实现

return func(*args, **kwargs)

return wrap_func

def after(self):

pass

@loginfo(info='info2')

def func1():

pass

# Output:

# func1 was called

# info: info1

再通过继承loginfo类,扩展装饰器的功能:

class loginfo_after(loginfo):

def __init__(self, info2='info2', *args, **kwargs):

self.info2 = info2

super(loginfo_after, self).__init__(*args, **kwargs)

def after(self):

print('after: %s' % self.info2)

@loginfo_after()

def func2():

pass

func2()

# Output:

# func2 was called

# info: info1

# after: info2

以上这篇老生常谈Python进阶之装饰器就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

本文标题: 老生常谈Python进阶之装饰器

本文地址: http://www.cppcns.com/jiaoben/python/190545.html

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

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

相关文章

LeetCode 02.两数相加

原题链接 解题思路: 本题可以使用模拟法,从链表的结点中提取出val逐个相加,没有值取0。并且记录进位,每个节点只保留个位数,所以需要使用sum与10取模,如果最高位存在进位则需要在最后添加一个val为1的节点…

apache ignite_从In Memory Data Grid,Apache Ignite快速入门

apache igniteIMDG或内存数据网格不是内存中关系数据库,NOSQL数据库或关系数据库。 它是另一种软件数据存储库。 数据模型分布在单个位置或多个位置的许多服务器上。 这种分布称为数据结构。 这种分布式模型被称为“无共享”架构。 IMDG具有以下特征: 所…

bvp解算器是什么_那些学习了编程的中学生,为什么会更可能成功?

来源 | 异步当你看到这个题目,或许会想,这不是搞笑吗?众所周知,高等数学是编程的基础和前提,而说起程序编写员,在普通人眼里就是数学学霸的代名词,人们往往会把它和那些数学天才的名字联系在一起…

Leetcode 08. 字符串转换整数 (atoi)

原题链接 1.字符 0~~~~~9 分别对应整数 48~~~~~57 2.先过滤空白 3.确定前面所带的符号 4. long long res 0; res res * 10 str[k] - 0; 可以通过此方法从左到右高位逐个累加。 class Solution { public:int myAtoi(string str) {long long res 0;int k 0;while…

maven与spring_与Spring和Maven签约首个SOAP服务

maven与spring1.简介 在本教程中,我们将学习使用JAX-WS,Spring和Maven实施合同优先的SOAP服务应用程序。 这是使用合同优先还是代码优先方法的更多设计决定。 在开发基于SOAP的Web服务应用程序时使用应用合同优先的方法最显着的好处是,可以在…

如何维持手机电池寿命_充电小知识:你知道如何正确充电吗?这几种充电方式最损害电池...

目前基本上大部分人都至少有一部智能手机,智能手机基本上都需要每日一充,你的充电方式会不会损伤电池呢?有部分消费者认为要等到手机电量耗尽后再充电,还有人认为手机充电要充至100%才能拔下来,有人觉得充电宝等产品给…

【开放集检测】OpenGAN: Open-Set Recognition via Open Data Generation 论文阅读

文章目录 英语积累为什么使用GAN系列网络进行开放集检测摘要1. 前言2. 相关工作开集检测基于GAN网络的开集检测基于暴露异常数据的开集检测 3. OpenGAN3.1 公式建模3.1.1 二分类方法存在问题如何解决 3.1.2 使用合成数据存在问题如何解决 3.1.3 OpenGAN3.1.4 模型验证 3.2 先前…

LeetCode 27.移除元素

原题链接 /** lc appleetcode.cn id27 langcpp** [27] 移除元素标签:拷贝覆盖主要思路是遍历数组nums,每次取出的数字变量为num,同时设置一个下标ans在遍历过程中如果出现数字与需要移除的值不相同时,则进行拷贝覆盖nums[ans] n…

hotspot 默认 gc_默认HotSpot最大直接内存大小

hotspot 默认 gc在我以前的博客文章热点选项中的Java 8改进的文档 ,我写的误解围绕热点JVM非标准的默认设置选项 -XX:MaxDirectMemorySize 。 在本文中,我介绍了一种确定HotSpot JVM中“默认”最大直接内存大小的简单方法。 Java启动器的Java 8文档对-X…

python控制电脑休眠唤醒键_每当计算机从休眠状态唤醒时,都运行python脚本

我在python上编写了一个小脚本,该脚本从控制台调用命令行以使linux机器休眠(或在更改一个单词的情况下将其自身关闭),然后在一段时间后唤醒.通过watch命令一次又一次地调用该命令.import osimport timeos.system("watch -n 20 sudo rtcwake -u -s 10 -m mem")因此,在…

sso集成shiro_Keycloak SSO集成到jBPM和Drools Workbench中

sso集成shiro介绍 单一登录(SSO)和相关令牌交换机制正在成为Web上不同环境中身份验证和授权的最常见方案,尤其是在迁移到云中时。 本文讨论了Keycloak与jBPM或Drools应用程序的集成,以便使用Keycloak上提供的所有功能。 Keycloak…

LeetCode 01. 两数之和

原题 分析: 1.根据题意,首先需要将要数据选择一个合适的 数据结构模型。 因为是对应相关联,所以我们选择unordered_map 2.因为是一组数,所以用数组 ,将数值与数组下标对应起来 3.已知两数之和,从数组第…

python中自带的模块_python中的模块详解

概念python中的模块是什么?简而言之,在python中,一个文件(以“.py”为后缀名的文件)就叫做一个模块,每一个模块在python里都被看做是一个独立的文件。模块可以被项目中的其他模块、一些脚本甚至是交互式的解析器所使用&#xff0c…

剑指 Offer 51-----59

剑指 Offer 55 - I. 二叉树的深度 解题思路: class Solution { public:int maxDepth(TreeNode* root) {if(rootNULL)return 0;int lmaxDepth(root->left);int rmaxDepth(root->right);return (l>r?l:r)1;} };

jbpm 和 drools_jBPM和Drools工作台中的用户和组管理

jbpm 和 drools介绍 本文讨论了一项新功能,该功能允许使用集成在jBPM和Drools Workbenches中的直观友好的用户界面来管理应用程序的用户和组。 用户和组管理 在安装,设置和使用此功能之前,本文讨论了一些以前的概念,需要进一步理…

剑指 Offer 01-----20

剑指 Offer 03. 数组中重复的数字 解题思路,使用STL中的set,逐个读入vector中的每一个元素,使用set进行对比,如果set中存在会返回1,这时直接返回该元素即可;如果set中没有可以insert这个元素到set&#xf…

python filter函数中写none_Python3基础 filter 第一个参数为NONE时 结果只返回为True的对象...

Python : 3.7.0OS : Ubuntu 18.04.1 LTSIDE : PyCharm 2018.2.4Conda : 4.5.11typesetting : Markdowncode"""Author : 行初心Date : 18-9-23Blog : www.cnblogs.com/xingchuxinGitee : gitee.com/zhichengjiu"""def main():# 过滤器# 通过 过滤…

从事java编程技能要求_5道Java视频课程,提高您的编程技能

从事java编程技能要求作为Web开发人员,跟上技术知识可能会很棘手。 新技术似乎每天都在弹出,而基本技术也看到了重复迭代的浪潮,增加了新的功能。 Java开发人员应该做什么? 这是在线教育平台发挥作用的地方。 它们可以帮助您快速…

常见算法核心思想

双指针算法 1.双指针算法主要是为了提高朴素算法的复杂度&#xff0c;即O(n^2)的算法&#xff0c;优化为O(n)的算法。 2.常见模板 for (int i 0, j 0; i < n; i ) {while (j < i && check(i, j)) j ;// 具体问题的逻辑 } 常见问题分类&#xff1a;(1) 对于…

sqlserver存储过程加锁后怎么解锁_【缺陷周话】第59期:重复加锁

聚焦源代码安全&#xff0c;网罗国内外最新资讯&#xff01;*声明&#xff1a;《缺陷周话》栏目系列文章由奇安信代码卫士团队原创出品。未经许可&#xff0c;禁止转载。转载请注明“转自奇安信代码卫士 www.codesafe.cn”。代码审计是使用静态分析发现源代码中安全缺陷的方法&…