python中的装饰器

装饰器是为了解决以下描述的问题而产生的方法

我们在已有的函数代码的基础上,想要动态的为这个函数增加功能而又不改变原函数的代码

例如有三个函数:

deff1(x):returnxdeff2(x):return x*xdeff3(x):return x*x*x

而我们想为这三个函数增加一个函数调用打印功能 类似print("call f1()")

如果我们直接修改的话,需要对每个函数的内部进行改写。

所以为了简化代码,我们可以使用python内置的@装饰器的方法,可以做到修饰函数的功能

Python的 decorator 本质上就是一个高阶函数,它接收一个函数作为参数,然后,返回一个新函数。

装饰器可以极大地简化代码,避免每个函数写重复性代码

不带参数的decorator

例如我们可以编写一个@log可以打印函数调用的装饰器

deflog(f):deffn(x):print ('call' + f.__name__ + '()...')returnf(x)return fn

然后我们可以测试一下

@logdeff1(x):returnx

a=f1(1)

print(a)

结果

call f1()...1

但是,对于参数不是一个的函数,调用将报错:

@logdefadd(x, y):return x +yprint (add(1, 2))

Traceback (most recent call last):

File"D:/pythonwork/cvworktest/final/practice.py", line 12, in

print (add(1, 2))

TypeError: fn() takes1 positional argument but 2 were given

这是因为add() 函数需要传入两个参数,但是 @log 写死了只含一个参数的返回函数。

要让 @log 自适应任何参数定义的函数,可以利用Python的 *args 和 **kw,保证任意个数的参数总是能正常调用:

deflog(f):def fn(*args, **kw):print ('call' + f.__name__ + '()...')return f(*args, **kw)return fn

现在,对于任意函数,@log 都能正常工作。

带参数decorator

上面的@log不带任何参数,同样我们可以编写一个带参数的decorator

例如如果有的函数非常重要,希望打印出'[INFO] call xxx()...',有的函数不太重要,希望打印出'[DEBUG] call xxx()...',这时

log函数本身就需要传入'INFO'或'DEBUG'这样的参数,类似这样:

@log('DEBUG')defmy_func():pass

我们把它翻译成高阶函数就是这样:

my_func = log('DEBUG')(my_func)

展开:

log_decorator = log('DEBUG')

my_func= log_decorator(my_func)

又相当于:

log_decorator = log('DEBUG')

@log_decoratordefmy_func():pass

所以,带参数的log函数首先返回一个decorator函数,再让这个decorator函数接收my_func并返回新函数:

deflog(content):deflog_decorator(f):def fn(*args, **kw):print ('[%s] %s()...' % (content, f.__name__))return f(*args, **kw)returnfnreturnlog_decorator

@log('DEBUG')deftest():pass

print (test())

结果:

[DEBUG] test()...

None

decorator的注意事项:

经过@decorator“改造”后的函数,和原函数相比,除了功能多一点外,还有很重要的一点就是函数自身的改变

在没有decorator的情况下,打印函数名:

deff1(x):pass

print (f1.__name__)

结果:

f1

有decorator的情况下,再打印函数名:

deflog(f):def wrapper(*args, **kw):print ('call...')return f(*args, **kw)returnwrapper

@logdeff2(x):pass

print (f2.__name__)

结果:

wrapper

由于decorator返回的新函数函数名已经不是'f2',而是@log内部定义的'wrapper'。这对于那些依赖函数名的代码就会失效。decorator还改变了函数的__doc__等其它属性。如果要让调用者看不出一个函数经过了@decorator的“改造”,就需要把原函数的一些属性复制到新函数中:

deflog(f):def wrapper(*args, **kw):print ('call...')return f(*args, **kw)

wrapper.__name__ = f.__name__wrapper.__doc__ = f.__doc__

return wrapper

这样写decorator很不方便,因为我们也很难把原函数的所有必要属性都一个一个复制到新函数上,所以Python内置的functools可以用来自动化完成这个“复制”的任务:

importfunctoolsdeflog(f):

@functools.wraps(f)def wrapper(*args, **kw):print ('call...')return f(*args, **kw)return wrapper

注意:对于函数的参数信息哦我们无法确定,因为装饰器与原函数的参数名不一定一样

装饰器的注意事项python_python中的装饰器decorator相关推荐

  1. python类装饰器详解-Python类中的装饰器在当前类中的声明与调用详解

    我的Python环境:3.7 在Python类里声明一个装饰器,并在这个类里调用这个装饰器. 代码如下: class Test(): xx = False def __init__(self): pa ...

  2. python在类内部使用装饰器_python – 如何在类中使用装饰器

    我知道有类似的问题,但我的情况有些不同:参考代码: class MyClass(object): def __init__(self, log_location) self.logs = loggin ...

  3. tableau获取筛选器值_认识Tableau中的筛选器

    Tableau中的筛选器: (1)提取筛选器(2)数据源筛选器(3)上下文筛选器(4)维度筛选器(5)度量筛选器(6)参数筛选器(7)表计算筛选器(8)页面筛选器 对筛选器进行简单的分类: 数据层(提 ...

  4. c#中索引器是什么_C#中的索引器

    c#中索引器是什么 An Indexer is a special feature of C# to use an object as an array. If you define an index ...

  5. java类包装器有什么用_Java中的包装器类

    java类包装器有什么用 Wrapper class in java are the Object representation of eight primitive types in java. A ...

  6. 从原理到实践:装饰器模式如何在项目中落地详解(给原对象增加新的行为和功能)

    装饰器模式---- 不修改原始对象,给原对象增加新的行为和功能. 2.1.概念 装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许动态地向对象添加额外的功能,而无需修改其原始 ...

  7. tomcat jar包_tomcat学习|tomcat中的类加载器

    开头说两句 小刀博客: http://www.lixiang.red 小刀公众号: 程序员学习大本营 学习背景 上期我们聊到了tomcat中各个组件在默认值,在其中,我们看到了有关类加载器的代码, 如 ...

  8. tomcat jar包编译后变成文件夹_tomcat学习|tomcat中的类加载器

    开头说两句 小刀博客: https://www.lixiang.red 小刀公众号: 程序员学习大本营 学习背景 上期我们聊到了tomcat中各个组件在默认值,在其中,我们看到了有关类加载器的代码, ...

  9. (转)spring中的拦截器(HandlerInterceptor+MethodInterceptor)

    1.  过滤器跟拦截器的区别 在说拦截器之前,不得不说一下过滤器,有时候往往被这两个词搞的头大. 其实我们最先接触的就是过滤器,还记得web.xml中配置的<filter>吗~ 你应该知道 ...

最新文章

  1. DLT645规约学习笔记
  2. Python 中的用户自定义类型
  3. 用Tableau画圆形网络关系图
  4. 打开word时出现“在加载ThisDocument时出现错误”
  5. Servlet和JSP学习指导与实践(二):Session追踪
  6. 地线与接地螺丝_快来看看新能源电动汽车充电时,地线的安装情况吧!
  7. UI设计|搭配色彩素材专辑,轻松掌握要点
  8. linux重启后mysql无法启动_Linux重启后MySQL数据库文件全部丢失MySQL无法启动
  9. 图像处理基本算法-直方图均衡
  10. 1、lo4j.properties
  11. 初识 Proxysql
  12. 6.6使用环境变量配置外部环境
  13. python获取程序运行路径
  14. 机器学习实战——3.4 示例:使用决策树预测隐形眼镜类型
  15. 银行与沪深300走势对比
  16. android各版本用户量,谷歌公布:Android用户手机系统版本份额分布
  17. 洗扑克牌 (乱数排序)
  18. ..\Watch\alarm.c(149): error: #268: declaration may not appear after executable statement in block
  19. Incomplete Multimodal Learning(不完整多模态学习)
  20. 服务器防御基础(常见的几种攻击手段以及应对方式)

热门文章

  1. php import用法,JavaScript中import怎么使用?
  2. dqs server sql_SQL-Server(一)数据库的基本概念
  3. cesium 设置时间_Cesium应用篇:3控件(1)Clock
  4. inotify+rsync实现实时同步部署
  5. JavaScript实现数除以二divideByTwo算法(附完整源码)
  6. OpenCASCADE绘制测试线束:数据交换命令之XDE 形状命令
  7. OpenCASCADE:Foundation Classes简介
  8. wxWidgets:wxSizerFlags类用法
  9. wxWidgets:wxPickerBase类用法
  10. boost::mp11::mp_replace_if相关用法的测试程序