文档章节

Python装饰器详解

SEOwhywhy
 SEOwhywhy
发布于 2018/11/17 19:48
字数 1675
阅读 2
收藏 0

  1.闭包函数
  
  在看装饰器之前,我们先来搞清楚什么是闭包函数。python是一种面向对象的编程语言,在python中一切皆对象,这样就使得变量所拥有的属性,函数也同样拥有。
  
  这样我们就可以理解在函数内创建一个函数的行为是完全合法的。
  
  下面是一个简单的闭包例子:
  
  复制代码
  
  # 定义一个函数
  
  def test(number_out):
  
  # 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个内部函数以及用到的一些变量称之为闭包
  
  def test_in(number_in):
  
  print("number_out:%d"www.365soke.com % number_out)
  
  print("in test_in 函数, number_in is %d" % number_in)
  
  return number_out+number_in
  
  # 其实这里返回的就是闭包的结果
  
  return test_in
  
  # 给test函数赋值,这个20就是给参数number_out
  
  ret = test(20)
  
  # 注意这里的100其实给参数number_in
  
  print(ret(100))
  
  复制代码
  
  运行结果:
  
  闭包:即两个函数嵌套,外部函数返回内部函数的引用,外部函数一定会传入参数,外部函数起的是交换引用的作用.
  
  闭包从语法上看非常简单,但是却有强大的作用。闭包可以将其自己的代码和作用域以及外部函数的作用结合在一起。
  
  总结:什么函数可以被称为闭包函数呢?主要是满足两点:函数内部定义的函数;引用了外部变量但非全局变量。
  
  2..什么是装饰器?
  
  有了闭包函数的概念,我们再去理解装饰器会相对容易一些。python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象。装饰器函数的外部函数传入我要装饰的函数名字,返回经过修饰后函数的名字;内层函数(闭包)负责修饰被修饰函数。从上面这段描述中我们需要记住装饰器的几点属性,以便后面能更好的理解:
  
  实质: 是一个函数
  
  参数:是你要装饰的函数名(并非函数调用)
  
  返回:是装饰完的函数名(也非函数调用)
  
  作用:为已经存在的对象添加额外的功能
  
  特点:不需要对对象做任何的代码上的变动
  
  3.装饰器的作用
  
  装饰器的作用: python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。
  
  一般而言,我们要想拓展原来函数代码,最直接的办法就是侵入代码里面修改,但这种方法有弊端,因为修改原代码不能保证原代码的其他模块功能的有效性,而使用装饰器能完美解决这一问题。
  
  python装饰器有很多经典的应用场景,比如:插入日志、性能测试、事务处理、权限校验等。装饰器是解决这类问题的绝佳设计。并且从引入中的列子中我们也可以归纳出:装饰器最大的作用就是对于我们已经写好的程序,我们可以抽离出一些雷同的代码组建多个特定功能的装饰器,这样我们就可以针对不同的需求去使用特定的装饰器,这时因为源码去除了大量泛化的内容而使得源码具有更加清晰的逻辑。
  
  4.几种常用装饰器
  
  4.1 函数的函数装饰器
  
  我们以函数添加计时功能为例,讲述函数装饰器。
  
  复制代码
  
  import time
  
  def decorator(func):
  
  def wrapper(*args, **kwargs):
  
  start_time = time.time(www.michenggw.com)
  
  func()
  
  end_time = time.time()
  
  print(end_time - start_time)
  
  return wrapper
  
  @decorator  # @decorator 相当于 test www.gcyl159.com= decorator(test)
  
  def test(www.yigouyule2.cn):
  
  time.sleep(0.8)
  
  print("test源代码")
  
  # 函数调用
  
  test(www.gcyl152.com)
  
  复制代码
  
  在上面代码中 test是我要装饰器的函数,我想用装饰器显示test函数运行的时间。@decorator这个语法相当于 执行 test= decorator(test),为test函数装饰并返回。
  
  再来看一下我们的装饰器函数  decorator,该函数的传入参数是func (即被装饰函数test的引用),返回参数是内层函数。这里的内层函数wrapper,其实就相当于闭包函数,它起到装饰给定函数的作用。
  
  4.2 被装饰的函数有不定长参数
  
  复制代码
  
  import time
  
  def timefun(func):
  
  def wrapped_func(*args, **kwargs):
  
  print("%s called at %s" % (func.__name__, time.ctime()))
  
  func(*args, **kwargs)
  
  return wrapped_func
  
  @timefun
  
  def foo(a, b, c, d="foo原代码"):
  
  time.sleep(0.8)
  
  print(a + b + c)
  
  print(d)
  
  foo(3, 5, 7)
  
  复制代码
  
  运行结果:
  
  wrapper参数为*args, **kwargs。 *args表示的参数以列表的形式传入;**kwargs表示的参数以字典的形式传入:
  
  从图中我们可以看到:凡是以key=value形式的参数均存在kwargs中,剩下的所有参数都以列表的形式存于args中。这里要注意的是:为了不破坏原函数的逻辑,我们要保证内层函数wrapper_func和被装饰函数func的传入参数和返回值类型必须保持一致。
  
  4.3. 类装饰器
  
  前面我们提到的都是让 函数作为装饰器去装饰其他的函数或者方法,那么可不可以让 一个类发挥装饰器的作用呢?答案肯定是可以的,python中一切皆对象,函数和类本质没有什么不一样。
  
  复制代码
  
  class Decorator(object):
  
  def __init__(self, f):
  
  self.f = f
  
  def __call__(self):
  
  print("decorator start")
  
  self.f()
  
  print("decorator end")
  
  @Decorator
  
  def func():
  
  print("func")
  
  func()
  
  复制代码
  
  这里值得注意的是:__call__()是一个特殊方法,它可将一个类实例变成一个可调用对象:
  
  func = Decorator(func) # func是类Decorator的一个实例
  
  func() # 实现了__call__()方法后,func可以被调用
  
  要使用类装饰器必须实现类中的__call__()方法,就相当于将实例变成了一个方法。

© 著作权归作者所有

SEOwhywhy
粉丝 8
博文 155
码字总数 342404
作品 0
私信 提问
转载:唐磊的个人博客《python中decorator详解》【转注:深入浅出清晰明了】

转载请注明来源:唐磊的个人博客《python中decorator详解》 前面写python的AOP解决方案时提到了decorator,这篇文章就详细的来整理下python的装饰器——decorator。 python中的函数即objects...

laugh2last
2015/08/17
1K
0
设计模式之:理解 Python 中的装饰器

1、问题 文章先由stackoverflow上面的一个问题引起吧,如果使用如下的代码: @makebold @makeitalic def say(): return "Hello" 打印出如下的输出: <b><i>Hello<i></b> 你会怎么做?最后给出......

大数据之路
2013/07/22
1K
0
Python知识点:理解和使用装饰器 @decorator

我在我的个人博客“猿人学网站”和公众号“猿人学Python”上写Python教程,有兴趣的可以关注公众号和网站。 Python的装饰器(decorator)是一个很棒的机制,也是熟练运用Python的必杀技之一。...

呆木木人儿
03/12
1K
4
一份来自 StackOverflow 的最佳 Python 装饰器教程

(给Python开发者加星标,提升Python技能) 翻译:可乐,校对:艾凌风 发布:Python开发者(id:PythonCoder) 注意: 这是一篇 StackOverflow 上的问题回答,因为这个回答很棒,所以我把它存...

Python开发者
04/25
0
0
Python3 与 C# 扩展之~基础拓展

上次知识回顾:https://www.cnblogs.com/dotnetcrazy/p/9278573.html 代码裤子:https://github.com/lotapp/BaseCode 在线编程:https://mybinder.org/v2/gh/lotapp/BaseCode/master 在线预览......

鲲逸鹏
2018/07/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Replugin借助“UI进程”来快速释放Dex

public static boolean preload(PluginInfo pi) { if (pi == null) { return false; } // 借助“UI进程”来快速释放Dex(见PluginFastInstallProviderProxy的说明) return PluginFastInsta......

Gemini-Lin
今天
4
0
Hibernate 5 的模块/包(modules/artifacts)

Hibernate 的功能被拆分成一系列的模块/包(modules/artifacts),其目的是为了对依赖进行独立(模块化)。 模块名称 说明 hibernate-core 这个是 Hibernate 的主要(main (core))模块。定义...

honeymoose
今天
4
0
CSS--属性

一、溢出 当内容多,元素区域小的时候,就会产生溢出效果,默认是纵向溢出 横向溢出:在内容和容器之间再套一层容器,并且内部容器要比外部容器宽 属性:overflow/overflow-x/overflow-y 取值...

wytao1995
今天
4
0
精华帖

第一章 jQuery简介 jQuery是一个JavaScript库 jQuery具备简洁的语法和跨平台的兼容性 简化了JavaScript的操作。 在页面中引入jQuery jQuery是一个JavaScript脚本库,不需要特别的安装,只需要...

流川偑
今天
7
0
语音对话英语翻译在线翻译成中文哪个方法好用

想要进行将中文翻译成英文,或者将英文翻译成中文的操作,其实有一个非常简单的工具就能够帮助完成将语音进行翻译转换的软件。 在应用市场或者百度手机助手等各大应用渠道里面就能够找到一款...

401恶户
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部