-
第三十六篇 装饰器和类的深层次理解
2019-11-27 22:58:29心得:遇到难以理解的东西,我愿意花费更多的时间去达到我想要的目的,那怕会很累很辛苦。 装饰器 先说说装饰器,装饰器今天看了好多篇的资料才彻底理解它的含义,但它真正的作用是用来装饰函数或者类,在其基本的...心得:遇到难以理解的东西,我愿意花费更多的时间去达到我想要的目的,那怕会很累很辛苦。
装饰器
先说说装饰器,装饰器今天看了好多篇的资料才彻底理解它的含义,但它真正的作用是用来装饰函数或者类,在其基本的方法下增加新的方法,不改变原方法。一般而言,我们要想拓展原来函数代码,最直接的办法就是侵入代码里面修改,例如:
import time def f(): print("hello") time.sleep(1) print("world")
这是我们最原始的的一个函数,然后我们试图记录下这个函数执行的总时间,那最简单的做法就是改动原来的代码:
import time def f(): start_time = time.time() print("hello") time.sleep(1) print("world") end_time = time.time() execution_time = (end_time - start_time)*1000 print("time is %d ms" %execution_time)
但是实际工作中,有些时候核心代码并不可以直接去改,所以在不改动原代码的情况下,我们可以再定义一个函数。(但是生效需要再次执行函数)
import time def deco(func): start_time = time.time() f() end_time = time.time() execution_time = (end_time - start_time)*1000 print("time is %d ms" %execution_time) def f(): print("hello") time.sleep(1) print("world") if __name__ == '__main__': deco(f) print("f.__name__ is",f.__name__) print()
这里我们定义了一个函数deco,它的参数是一个函数,然后给这个函数嵌入了计时功能。但是想要拓展这一千万个函数功能,
就是要执行一千万次deco()函数,所以这样并不理想!接下来,我们可以试着用装饰器来实现,先看看装饰器最原始的面貌。
import time def deco(f): def wrapper(): start_time = time.time() f() end_time = time.time() execution_time = (end_time - start_time)*1000 print("time is %d ms" %execution_time ) return wrapper @deco def f(): print("hello") time.sleep(1) print("world") if __name__ == '__main__': f()
这里的deco函数就是最原始的装饰器,它的参数是一个函数,然后返回值也是一个函数。
其中作为参数的这个函数f()就在返回函数wrapper()的内部执行。然后在函数f()前面加上@deco,
f()函数就相当于被注入了计时功能,现在只要调用f(),它就已经变身为“新的功能更多”的函数了,
(不需要重复执行原函数)。
扩展1:带有固定参数的装饰器
import time def deco(f): def wrapper(a,b): start_time = time.time() f(a,b) end_time = time.time() execution_time = (end_time - start_time)*1000 print("time is %d ms" % execution_time) return wrapper @deco def f(a,b): print("be on") time.sleep(1) print("result is %d" %(a+b)) if __name__ == '__main__': f(3,4)
扩展2:无固定参数的装饰器
import time def deco(f): def wrapper(*args, **kwargs): start_time = time.time() res = f(*args, **kwargs) end_time = time.time() execution_time_ = (end_time - start_time)*1000 print("time is %d ms" %execution_time) return res #函数的返回值(函数内return后才可以接收) return wrapper @deco def f(a,b): print("be on") time.sleep(1) print("result is %d" %(a+b)) return 1 #函数的返回值(这里的值) @deco def f2(a,b,c): print("be on") time.sleep(1) print("result is %d" %(a+b+c)) if __name__ == '__main__': f2(3,4,5) f(3,4)
多个装饰器存在时,自下而上一个一个的去装饰
def dec1(func): print("1111") def one(): print("2222") func() print("3333") return one def dec2(func): print("aaaa") def two(): print("bbbb") func() print("cccc") return two @dec1 @dec2 def test(): print("test test") test() 结果: aaaa 1111 2222 bbbb test test cccc 3333
带参数的装饰器:
# -*- coding: UTF-8 -*- """"================================================= @Project -> File :Django -> 二叉树之有序列表 @IDE :PyCharm @Author :爱跳水的温文尔雅的laughing @Date :2020/4/2 21:56 @Desc : ==================================================""" import time def out_args(out_args): def wrapper(f): def wrapper(*args, **kwargs): start_time = time.time() print(out_args) res = f(*args, **kwargs) end_time = time.time() execution_time_ = (end_time - start_time) * 1000 print("time is %d ms" % execution_time_) return res # 函数的返回值(函数内return后才可以接收) return wrapper return wrapper @out_args("外部参数") def f(a, b): print("be on") time.sleep(1) print("result is %d" % (a + b)) return 1 # 函数的返回值(这里的值) if __name__ == '__main__': c=f(1,2) print("c",c) #输出 外部参数 be on result is 3 time is 1000 ms c 1
类
Python内置装饰器在Python中有三个内置的装饰器,和类有关:
类属性:
属于类的公有属性;用类名调用,用类名修改可以永久性修改类属性;和用实例调用结果一样,用实例修改,只能修改当前实例的类属性。实例属性:
实例属性可以被实例方法用,使用方法为self.x实例方法:
定义的方法,可以调用类属性和实例属性类方法:
classmethod 使用装饰器进行装饰,接收的第一个参数为类的本身,主要用于对参数的预处理,可以访问类的属性。类中的静态方法:
staticmethod 是类静态方法,其跟成员方法的区别是没有 self 参数,并且可以在类不进行实例化的情况下调用property:
property 是属性的意思,表示可以通过通过类实例直接访问的信息当我们传入的参数,为一串字符串,并不符合对象属性接收的参数,我们的类属性就派上了用场,进行参数的预处理和访问类属性。
import re class People(): nation="china" #类属性 def __init__(self,name,age): self.name=name #实例属性 self.__age=age #设置私有变量 def get_info(self): #实例方法 print(self.name,self.__age) @classmethod #类方法 def pre_args(cls,obj,nation): #传递参数 name=re.findall(r'\w+',obj)[0] age=re.findall(r'\d+',obj)[0] person=cls(name,age) #实例化 print(cls.nation) return person @staticmethod #静态方法 def cal(a,b): print("两数之和为:",a+b) @property #可以访问私有变量 def change_age(self): return self.__age p1=People.pre_args("@tianjian#27","nation") #直接用类调用类方法 print(p1) p1.get_info() People.cal(3,5) #调用静态方法 p2=People("tian",26) print(p2.change_age) print(p2.__age) #不能访问私有变量
结果:
私有变量不能直接被访问china <__main__.People object at 0x7f2d8beaacc0> tianjian 27 两数之和为: 8 26 Traceback (most recent call last): File "cls_usage.py", line 67, in <module> print(p2.__age) AttributeError: 'People' object has no attribute '__age'
-
-
你必须知道的495个C语言问题
2015-05-08 11:09:255.17 说真的,真有机器用非零空指针吗,或者不同类型用不同的表示? 地址0上到底有什么? 5.18 运行时的整数值0转换为指针以后一定是空指针吗? 5.19 如何访问位于机器地址0处的中断向量?如果我将指针值设为0... -
疯狂的程序员
2012-07-18 18:05:32因为佩服他,跟他说了很多客套话,没想到一客套,让那男人更牛B起来:“想我堂堂一个程 序员,现在却在搞这个。唉……” 这时候,绝影才第一次听到“程序员”这个词。程序员是什么?他不知道。他问:“程序员能找到... -
《你必须知道的495个C语言问题》
2010-03-20 16:41:18内容简介 《你必须知道的495个C语言问题》以问答...5.17 说真的,真有机器用非零空指针吗,或者不同类型用不同的表示? 61 地址0 上到底有什么? 61 5.18 运行时的整数值0转换为指针以后一定是空指针吗? 61 5.19... -
你必须知道的495个C语言问题(高清版)
2010-03-31 16:24:095.17 说真的,真有机器用非零空指针吗,或者不同类型用不同的表示? 61 地址0 上到底有什么? 61 5.18 运行时的整数值0转换为指针以后一定是空指针吗? 61 5.19 如何访问位于机器地址0处的中断向量?如果我将... -
-
构建一个使用 Virtual-DOM 的前端模版引擎
2021-01-09 01:41:16用 jQuery 代码中会就混杂着很多的 DOM 操作,编码复杂且不便于维护;而重新渲染虽然省事,但是会导致一些性能、焦点消失的问题(具体可以看这篇博客介绍</a>)。 因为习惯了 MVVM ... -
你必须知道的495个C语言问题(PDF)
2009-09-15 10:25:475.8 但是如果NULL 的值改变了, 比如在使用非零内部空指针的机器 上, 难道用NULL (而不是0) 不是更好吗? . . . . . . . . . . . . . 24 5.9 用预定义宏#define Nullptr(type) (type *)0 帮助创建正确类型的 空指针。... -
自己动手写操作系统(含源代码).part2
2010-10-18 19:47:45首先是操作系统的名字改变了,原因在于虽然我们的试验性 OS从前辈们那里借鉴了很多东西,但其各个部分的设计(比如文件系统和内存管理)往往有其独特之处,所以我将原先的 Tinix(本意为 TryMinix)改成了新名字... -
自己动手写操作系统(含源代码).part1
2010-10-18 19:41:25首先是操作系统的名字改变了,原因在于虽然我们的试验性 OS从前辈们那里借鉴了很多东西,但其各个部分的设计(比如文件系统和内存管理)往往有其独特之处,所以我将原先的 Tinix(本意为 TryMinix)改成了新名字... -
健康类网站(课程设计)源码20130608
2013-06-09 09:49:03真的很对不起支持我的各位同胞们,经过一个小时的测试修改,终于完成了基本的测试修改工作,我以后还会继续努力的,希望各位继续支持我的前进。 2013.6.5更新内容: 新增了图片浏览模块,用户评论,浏览 数据库改变... -
C++程序设计语言(特别版)--详细书签版
2012-04-23 07:13:03已出版多部著作和译著,包括《程序设计语言基础》(译著,1990),《Mathematica数学软件系统的应用与程序设计》(1994),《从问题到程序——程序设计与C语言引论》(1999) [同作者作品] 计算机基础教程(上下)... -
C++程序设计语言(特别版)--课后习题源代码
2012-04-23 07:37:34已出版多部著作和译著,包括《程序设计语言基础》(译著,1990),《Mathematica数学软件系统的应用与程序设计》(1994),《从问题到程序——程序设计与C语言引论》(1999) [同作者作品] 计算机基础教程(上下)... -
C++程序设计语言(特别版)--源代码
2012-04-23 07:33:51已出版多部著作和译著,包括《程序设计语言基础》(译著,1990),《Mathematica数学软件系统的应用与程序设计》(1994),《从问题到程序——程序设计与C语言引论》(1999) [同作者作品] 计算机基础教程(上下)... -
Oracle Database 9i10g11g编程艺术:深入数据库体系结构(第2版)--详细书签版
2013-02-03 11:42:53CruiseYoung提供的带有详细书签的电子书籍目录 ... Oracle Database 9i/10g/11g编程艺术:深入数据库体系结构:第...例如11g引入dbms_parallel_execute包来帮助自动实现原来需要人工实现的并行化,以及引入PSQ来控制并行度,... -
人工智能全部课件和作业题
2013-01-11 22:00:10说实话,在老师快讲完第三章之前我还一直坐在靠后的位置看不清PPT,后来觉得还是要认真听讲,于是每次都是占前两排的座位,当然这种做法事后证明也是对的,看来有时候一念之差能改变很多。 针对这门课的内容没有... -
Oracle 9i & 10g编程艺术:深入数据库体系结构(09年度畅销榜TOP50)(08年度畅销榜TOP50)--详细书签版
2013-02-06 18:24:20学习Oracle时,很多书和资料都很有参考价值,特别是Oracle文档,更是全面地提供了我们想了解的信息。但是文档中没有实战用例,没有告诉我们哪些可行或者哪些不可行,什么情况下可行或者什么情况下不可行,为什么可行... -
-
-
计算机应用技术(实用手册)
2011-07-29 16:32:16让默认的就可以了,但是超频玩者是肯定不会放过任何可以提高性能的东西的,所以如果你想在这里让你的电脑提升一点性能的话,就必须慢慢试验,选择一个适当的参数才能让你的计算机达到性能和稳定的最佳状态!... -
VB课程设计俄罗斯方块
2011-02-25 10:46:55某些与坠落的玩具碎片和它们的形状有关的东西,使得哪怕新手也会很自然地企图把它们排列起来,并加以适当组合,就好似《俄罗斯方块》触动了我们某些内在的感官,使得哪怕是我们当中最杂乱无章的人也要把事情整理妥当... -
哈佛大学职业经理MBA全套讲义
2008-10-08 19:15:54为了训练一个管理人员获得熟练的技能,会要求他提交论文或报告,详细阐述政府法令、重大事件、自然灾害、消费者兴趣的改变、未来变化趋势等因素对公司发展可能产生的影响。即使他在这一方面做得象一个行业发言人一样... -
转来备用,以后慢慢学
2010-05-21 14:14:33在动作调板中单击右上角的三角形按钮,从弹出的菜单中选择载入动作,进入PhotoshopGoodiesActions目录下,其下有按钮、规格、命令、图像效果,文字效果、纹理、帧六个动作集,包含了很多实用的东西哟!另外,在该... -
极品ADSL+路由器驱动优化工具cfos_7.52和cfosspeed_5.12汉化特别版
2010-06-29 08:26:00A: 预设状态, cFos/cFosSpeed 都是 Ping 德国 cFos (不确定, 得 tracert 查查看), 但是外国往往必须经过很多 router 的转接, 所以笔者用 ping_dest= 这个命令 (cfos.ini or cfosspeed.ini) 去改变 Ping 的位置, 这个... -
深度剖析:如何实现一个 Virtual DOM 算法
2021-01-09 00:43:15经验丰富的你一定第一时间意识这样的做法会导致很多的问题。最大的问题就是这样做会很慢,因为即使一个小小的状态变更都要重新构造整棵 DOM,性价比太低;而且这样做的话,<code>input和... -
flash shiti
2014-03-14 10:32:4111. 全等(===)运算符和相同运算符基本相似,但是它们有一个很重要的区别 □ A. 全等(===)运算符执行数据类型的转换 □ B. 全等(===)运算符不执行数据类型的转换 □ C. 全等(===)运算符永远返回...