转载一篇写的不错的python装饰器

用 Numba 加速 Python 代码,变得像 C++ 一样快 Numba 是 python 的即时(Just-in-time)编译器,即当你调用 python 函数时,你的全部或部分代码就会被转换为“即时”执行的机器码,它将以你的本地机器码速度运行!它由 Anaconda 公司赞助,并得到了许多其他组织的支持。 阅读详情

Python装饰器与面向切面编程

新年好~  那么,很久没有更新了,其实想想也没多少可以写的,因为Python的文档似乎很全面的说……能做的差不多只有翻译和整理了,英文过关的朋友不妨直接去doc.python.org这里查看相关资料 :) 
转载请注明原作者和原文地址,多谢!

今天来讨论一下装饰器。装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。

1. 装饰器入门

1.1. 需求是怎么来的?

装饰器的定义很是抽象,我们来看一个小例子。

?
1
2
3
4
def  foo():
     print  'in foo()'
 
foo()

这是一个很无聊的函数没错。但是突然有一个更无聊的人,我们称呼他为B君,说我想看看执行这个函数用了多长时间,好吧,那么我们可以这样做:

?
1
2
3
4
5
6
7
8
import  time
def  foo():
     start =  time.clock()
     print  'in foo()'
     end =  time.clock()
     print  'used:' , end -  start
 
foo()

很好,功能看起来无懈可击。可是蛋疼的B君此刻突然不想看这个函数了,他对另一个叫foo2的函数产生了更浓厚的兴趣。

怎么办呢?如果把以上新增加的代码复制到foo2里,这就犯了大忌了~复制什么的难道不是最讨厌了么!而且,如果B君继续看了其他的函数呢?

1.2. 以不变应万变,是变也

还记得吗,函数在Python中是一等公民,那么我们可以考虑重新定义一个函数timeit,将foo的引用传递给他,然后在timeit中调用foo并进行计时,这样,我们就达到了不改动foo定义的目的,而且,不论B君看了多少个函数,我们都不用去修改函数定义了!

?
1
2
3
4
5
6
7
8
9
10
11
12
import  time
 
def  foo():
     print  'in foo()'
 
def  timeit(func):
     start =  time.clock()
     func()
     end = time.clock()
     print  'used:' , end -  start
 
timeit(foo)

看起来逻辑上并没有问题,一切都很美好并且运作正常!……等等,我们似乎修改了调用部分的代码。原本我们是这样调用的:foo(),修改以后变成了:timeit(foo)。这样的话,如果foo在N处都被调用了,你就不得不去修改这N处的代码。或者更极端的,考虑其中某处调用的代码无法修改这个情况,比如:这个函数是你交给别人使用的。

1.3. 最大限度地少改动!

既然如此,我们就来想想办法不修改调用的代码;如果不修改调用代码,也就意味着调用foo()需要产生调用timeit(foo)的效果。我们可以想到将timeit赋值给foo,但是timeit似乎带有一个参数……想办法把参数统一吧!如果timeit(foo)不是直接产生调用效果,而是返回一个与foo参数列表一致的函数的话……就很好办了,将timeit(foo)的返回值赋值给foo,然后,调用foo()的代码完全不用修改!

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#-*- coding: UTF-8 -*-
import  time
 
def  foo():
     print  'in foo()'
 
# 定义一个计时器,传入一个,并返回另一个附加了计时功能的方法
def  timeit(func):
     
     # 定义一个内嵌的包装函数,给传入的函数加上计时功能的包装
     def  wrapper():
         start =  time.clock()
         func()
         end = time.clock()
         print  'used:' , end -  start
     
     # 将包装后的函数返回
     return  wrapper
 
foo =  timeit(foo)
foo()

这样,一个简易的计时器就做好了!我们只需要在定义foo以后调用foo之前,加上foo = timeit(foo),就可以达到计时的目的,这也就是装饰器的概念,看起来像是foo被timeit装饰了。在在这个例子中,函数进入和退出时需要计时,这被称为一个横切面(Aspect),这种编程方式被称为面向切面的编程(Aspect-Oriented Programming)。与传统编程习惯的从上往下执行方式相比较而言,像是在函数执行的流程中横向地插入了一段逻辑。在特定的业务领域里,能减少大量重复代码。面向切面编程还有相当多的术语,这里就不多做介绍,感兴趣的话可以去找找相关的资料。

这个例子仅用于演示,并没有考虑foo带有参数和有返回值的情况,完善它的重任就交给你了 :)

2. Python的额外支持

2.1. 语法糖

上面这段代码看起来似乎已经不能再精简了,Python于是提供了一个语法糖来降低字符输入量。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import  time
 
def  timeit(func):
     def  wrapper():
         start =  time.clock()
         func()
         end = time.clock()
         print  'used:' , end -  start
     return  wrapper
 
@timeit
def  foo():
     print  'in foo()'
 
foo()

重点关注第11行的@timeit,在定义上加上这一行与另外写foo = timeit(foo)完全等价,千万不要以为@有另外的魔力。除了字符输入少了一些,还有一个额外的好处:这样看上去更有装饰器的感觉。

2.2. 内置的装饰器

内置的装饰器有三个,分别是staticmethod、classmethod和property,作用分别是把类中定义的实例方法变成静态方法、类方法和类属性。由于模块里可以定义函数,所以静态方法和类方法的用处并不是太多,除非你想要完全的面向对象编程。而属性也不是不可或缺的,Java没有属性也一样活得很滋润。从我个人的Python经验来看,我没有使用过property,使用staticmethod和classmethod的频率也非常低。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class  Rabbit( object ):
     
     def  __init__( self , name):
         self ._name =  name
     
     @staticmethod
     def  newRabbit(name):
         return  Rabbit(name)
     
     @classmethod
     def  newRabbit2( cls ):
         return  Rabbit('')
     
     @property
     def  name( self ):
         return  self ._name

这里定义的属性是一个只读属性,如果需要可写,则需要再定义一个setter:

?
1
2
3
@name .setter
def  name( self , name):
     self ._name =  name

2.3. functools模块

functools模块提供了两个装饰器。这个模块是Python 2.5后新增的,一般来说大家用的应该都高于这个版本。但我平时的工作环境是2.4 T-T

2.3.1. wraps(wrapped[, assigned][, updated]): 
这是一个很有用的装饰器。看过前一篇反射的朋友应该知道,函数是有几个特殊属性比如函数名,在被装饰后,上例中的函数名foo会变成包装函数的名字wrapper,如果你希望使用反射,可能会导致意外的结果。这个装饰器可以解决这个问题,它能将装饰过的函数的特殊属性保留。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import  time
import  functools
 
def  timeit(func):
     @functools .wraps(func)
     def  wrapper():
         start =  time.clock()
         func()
         end = time.clock()
         print  'used:' , end -  start
     return  wrapper
 
@timeit
def  foo():
     print  'in foo()'
 
foo()
print  foo.__name__

首先注意第5行,如果注释这一行,foo.__name__将是'wrapper'。另外相信你也注意到了,这个装饰器竟然带有一个参数。实际上,他还有另外两个可选的参数,assigned中的属性名将使用赋值的方式替换,而updated中的属性名将使用update的方式合并,你可以通过查看functools的源代码获得它们的默认值。对于这个装饰器,相当于wrapper = functools.wraps(func)(wrapper)。

2.3.2. total_ordering(cls): 
这个装饰器在特定的场合有一定用处,但是它是在Python 2.7后新增的。它的作用是为实现了至少__lt__、__le__、__gt__、__ge__其中一个的类加上其他的比较方法,这是一个类装饰器。如果觉得不好理解,不妨仔细看看这个装饰器的源代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
53   def  total_ordering( cls ):
54       """Class decorator that fills in missing ordering methods"""
55       convert =  {
56           '__lt__' : [( '__gt__' , lambda  self , other: other < self ),
57                      ( '__le__' , lambda  self , other: not  other < self ),
58                      ( '__ge__' , lambda  self , other: not  self  < other)],
59           '__le__' : [( '__ge__' , lambda  self , other: other < =  self ),
60                      ( '__lt__' , lambda  self , other: not  other < =  self ),
61                      ( '__gt__' , lambda  self , other: not  self  < =  other)],
62           '__gt__' : [( '__lt__' , lambda  self , other: other > self ),
63                      ( '__ge__' , lambda  self , other: not  other > self ),
64                      ( '__le__' , lambda  self , other: not  self  > other)],
65           '__ge__' : [( '__le__' , lambda  self , other: other > =  self ),
66                      ( '__gt__' , lambda  self , other: not  other > =  self ),
67                      ( '__lt__' , lambda  self , other: not  self  > =  other)]
68       }
69       roots =  set ( dir ( cls )) & set (convert)
70       if  not  roots:
71           raise  ValueError( 'must define at least one ordering operation: < > <= >=' )
72       root =  max (roots)       # prefer __lt__ to __le__ to __gt__ to __ge__
73       for  opname, opfunc in  convert[root]:
74           if  opname not  in  roots:
75               opfunc.__name__ =  opname
76               opfunc.__doc__ =  getattr ( int , opname).__doc__
77               setattr ( cls , opname, opfunc)
78       return  cls

本文到这里就全部结束了,有空的话我会整理一个用于检查参数类型的装饰器的源代码放上来,算是一个应用吧 :)



Unity技能系统核心:从理论到实践构建可扩展的Buff管理器 本文深入探讨了Unity游戏开发中构建可扩展技能系统的核心——Buff管理器。通过剖析三层架构(数据、逻辑、渲染)与独立组件管理模式,提供了从Buff数据定义、管理器核心实现到可视化编辑器搭建的完整实践方案,旨在解决技能系统维护难题,提升开发效率与代码质量。 阅读详情

相关推荐

ESP32-P4实战:LVGL V9.4 PPA加速配置与性能对比

本文详细介绍了如何在ESP32-P4平台上配置LVGL V9.4的PPA硬件加速功能,通过启用PPA加速显著提升图形处理性能并降低CPU占用率。文章包含环境准备、配置步骤、性能对比及常见问题解决方案,帮助开发者高效利用ESP32-P4的PPA加速器优化嵌入式GUI应用。

rice5的博客 1189

Python装饰器与面向切面编程

新年好~ 那么,很久没有更新了,其实想想也没多少可以写的,因为Python的文档似乎很全面的说……能做的差不多只有翻译和整理了,英文过关的朋友不妨直接去doc.python.org这里查看相关资料 :) 转载请注明原作者和原文地址,多谢! 今天来讨论一下装饰器。装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类...

weixin_30532759的博客 877

ai数字人系统部署

这段代码实现了基本的语音交互闭环,用户通过语音输入问题,数字人识别语音后进行自然语言理解并生成回复,再将回复转换为语音输出。但实际应用中的 AI 数字人系统更为复杂,如形象渲染需专业图形引擎(如 Unity、Unreal Engine),自然语言处理也会涉及更复杂的模型微调及多轮对话管理等。一个完整的 AI 数字人系统涵盖形象生成、自然语言处理、动作控制等多个复杂功能,下面为你提供一个 Python 示例,整合多个库来实现数字人基础功能,包括语音交互、简单的自然语言理解以及通过虚拟形象展示对话。

weixin_ggwwsscc的博客 369

@njit(parallel=True) 和@njit的区别

njit 和 @njit(parallel=True) 是来自 Numba 库的两个装饰器,用于加速 Python 代码的执行。Numba 是一个开源 JIT(Just-In-Time)编译器,可以将 Python 和 NumPy 代码转换为机器码,从而提高性能。

qq_41327049的博客 1417

RK3568 解决MIPI屏幕开机只显示uboot logo的问题

之前写过一篇文章介绍了RK3568驱动MIPI屏幕的方法,这次产品迭代,硬件改版,选型的新的屏幕了。所以再次开启调试屏幕的过程。本以为会和上次一样会轻车熟路,事情总是事与愿违,同样的路,遇到新的坑。

fhqlongteng的博客 5425

Winform美化框架AntdUI中Table的使用方法

使用核心注意点: 数据模型中属性名需要完全与new Column里的列名一致否则添加数据源则无法读取到详细内容。

wevix的博客 3676

python 装饰器

python装饰器是干嘛的  就是现在又一个函数方法 不想改动他本身的代码  又想给他增加新的功能  就是装饰器   这样说比较笼统 大概就是这个意思  先来看代码  def w1(func): def inner(): print("---新增功能----") func() return inner @w1 def f1(): pri...

养猪专业户 195

Nacos 从困惑到蒙圈(9)Nacos 适配 达梦数据库【最新版】

介绍Nacos适配达梦数据库的详细步骤,包括对最新版本的支持改造。

甘蓝的专栏 1376

@njit 进行负采样,效率提升近40倍

慢吞吞的老方法: 推荐算法中常常会用到BPR损失,在进行负采样时,常用方法为: def UniformSample_original_python(dataset): """ the original impliment of BPR Sampling in LightGCN :return: np.array """ total_start = time() user_num = dataset.trainDataSize users

strawberry47的博客 3147

YOLO26 旋转框检测 OBB 技术:角度预测与解码优化

YOLO26旋转框检测技术通过CSL角度编码有效解决了OBB检测中的周期性问题。该技术采用5参数表示法(cx,cy,w,h,θ),在检测头中分别处理分类、回归和角度预测。核心创新点包括:1)使用高斯或三角窗口的CSL编码对角度进行平滑表示;2)通过加权平均解码角度,避免边界不连续问题。该方法在遥感、文本检测等需要精确方向信息的场景中表现优异,相比传统HBB框可提升定位精度30%以上,同时保持了YOLO系列的高效特性。

一键难忘的博客 521

AI驱动芯片设计的端到端验证:AI应用架构师的全流程指南

想象你要建造一座1000层的超级摩天大楼,每个房间都有独特的功能,管道、电路、电梯系统交织如迷宫。传统的检查方式是派1000个工程师逐层逐房手动检查,耗时十年且仍可能遗漏火灾隐患。这就是今天芯片设计面临的困境:7nm芯片含百亿晶体管,相当于百亿个"房间",传统验证方法(人工编写测试用例、随机仿真)已难以应对。本文的目的,是为AI应用架构师提供一份"AI驱动芯片验证导航图",范围涵盖从验证需求分析到芯片签核的全流程,包括AI模型如何融入传统验证工具链、数据如何驱动验证效率提升、以及端到端闭环系统的构建方法。

2501_92132293的博客 1240

python3 装饰器_Python中自带的三个装饰器

说到装饰器,就不得不说python自带的三个装饰器:1、@property 将某函数,做为属性使用@property 修饰,就是将方法,变成一个属性来使用。class A():@propertydef pfunc(self):return self.value@pfunc.setterdef pfunc(self,value):self.value = value@propertydef pfun...

weixin_39884074的博客 99

权重衰减weight_decay参数从入门到精通

Weight Decay是一个正则化技术,作用是**抑制模型的过拟合**,以此来提高模型的泛化性。 目前网上对于Weight Decay的讲解都比较泛,都是短短的几句话,但对于其原理、实现方式大多就没有讲解清楚,本文将会逐步解释weight decay机制。

iioSnail的博客 4万+

Python之装饰器入门

概述:python装饰器属于进阶必学的,很多人刚学是很难明白的,这里用比较容易懂的方式简单讲一下:(注意:这里需要函数的基础知识) 第一步: 我们有一个函数,比如一个求和的函数: def sum_test(): sum=12+20 print(sum) 如果我们需要去再函数中前后加入开始跟结束打印用于调试,常规可能处理的办法是去修改这个函数,如下操作:...

187

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

python的staticmethod,classmethod和装饰器以及闭包

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

CSUXD的博客 309

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Python装饰器,json,pickle

装饰器 定义:本质是函数,装饰其它函数是为了给其添加新功能; 原则:1.不能修改被装饰的函数的源代码 2.不能修改被装饰的函数的调用方式 实现装饰器知识储备: 1.函数即变量; 2.高阶函数 3.嵌套函数 高价函数+嵌套函数=装饰器 下面我哪一个案例来讲一讲 1 import time 2 def timmer(func): 3 ...

atk34332的博客 150

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Python 装饰器实例

retry 偶然看到一篇文章,想到了前几天的一个需求,git pull性能不稳,需要加入重试机制,正好这个装饰器的实例符合这样的场景。 # coding:utf-8 import time import logging import socket from functools import wraps logging.basicConfig(level=logging.DEBUG) def r...

weixin_34255793的博客 106

Python装饰器详解

@author StormMa @date 2017-06-09 生命不息,奋斗不止! 开始之前 第一次接触Python的时候就是直接开始写一些爬虫或者是使用django写简单的web应用,但是最近想回头来看看Python中好玩的特性或者是基础。今天就来看一下装饰器的使用,其实感觉Python中的装饰器,有点类似于Java中的Aspect。就像你在一个方法中处理主要的业务逻辑,如果要想在

StormMaybin的博客 1771

python闭包与装饰器的代码解释

代码: 闭包 #coding=utf-8 #闭包:对外部作用域的变量进行引用的内部函数 """ 闭包的条件: 一个闭包至少要有两层嵌套关系 内嵌的函数要引用外部函数的变量 闭包必须返回嵌套函数 """ def bibao_one(): Jay = "哎哟不错哦" def bibao_two(): print(Jay) return bibao_two() #执行闭包 execute = bibao_one() execute 执行结果 装饰器 """

宝藏女孩的成长日记 382

Python装饰器

文章来源:http://www.cnblogs.com/wilber2013/p/4657155.html 装饰模式有很多经典的使用场景,例如插入日志、性能测试、事务处理等等,有了装饰器,就可以提取大量函数中与本身功能无关的类似代码,从而达到代码重用的目的。下面就一步步看看Python中的装饰器。 一个简单的需求 现在有一个简单的函数"myfunc",想通过代码得到这个函数的...

weixin_34085658的博客 81

多个装饰器装饰一个函数

# def debug(func): # # def wrapper(): # # print ("[DEBUG]: enter {}()".format(func.__name__)) # # return func() # # return wrapper # # @debug # # def say_hello(): # # ...

weixin_30563319的博客 86

Python闭包及装饰器

Python闭包 先看一个例子: def outer(x): def inner(y): return x+y return innder add = outer(8) print add(6) 我们定义了一个方法outer,方法内部又定义了一个方法inner,方法outer返回值为内部定义的方法inner。 同时,内部方法innde...

weixin_30875157的博客 119

python 装饰器,生成器,迭代器

装饰器 作用:当我们想要增强原来已有函数的功能,但不想(无法)修改原函数,可以使用装饰器解决 使用: 先写一个装饰器,就是一个函数,该函数接受一个函数作为参数,返回一个闭包,而且闭包中执行传递进来的函数,闭包中可以在函数执行的前后添加一些内容。 在需要装饰的函数前添加@装饰器名就可以使用了,如: @zhuangshiqidef show(): pas...

weixin_33709364的博客 81

小白成长之路:初识python(五) --python装饰器

flag = "=======================装饰器============================="#定义的装饰器函数# def outer(func):# def inner():# print('加装饰器')# r = func()# return r# return inner## @outer# d...

weixin_30328063的博客 108

利用Python多线程限制 http 真实请求时间或限制函数最大执行时间的装饰器

  这段时间在制作一个爬虫的时候发现了一个比较神奇的事情 python requests 包发起请求的时候设置 timeout 参数 竟然不起作用? what 你要弄啥幺蛾子嘞,  后来各种找原因终于在别人的提醒下又看了下 requests 的文档才发现原来 timeout 设置超时只是指发起到对方服务器接受到请求这段时间,原文:timeout 仅对连接过程有效,与响应体的下载无关。 timeo...

本与太阳肩并肩,何须再用飞上天 1994
上一篇: 开发总结
下一篇: python的 public 、private成员变量、成员函数总结
乔巴好萌
博客等级 码龄15年 228粉丝 47原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值