您可能感兴趣的话题:

Python

核心提示:   这篇文章主要介绍了Python的装饰器模式与面向切面编程详解,概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能,本文详细了装饰器模式的方方面面,然后引出面向切面编程知识,需要的朋友可以参考下。

这篇文章主要介绍了Python的装饰器模式与面向切面编程详解,概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能,本文详细了装饰器模式的方方面面,然后引出面向切面编程知识,需要的朋友可以参考下

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

装饰器入门  1.1. 需求是怎么来的?  装饰器的定义很是抽象,我们来看一个小例子。   代码如下:  def foo():  print 'in

foo()'  foo()  这是一个很无聊的函数没错。但是突然有一个更无聊的人,我们称呼他为B君,说我想看看执行这个函数用了多长时间,好吧,那么我们可以这样做:  代码如下:  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君看了多少个函数,我们都不用去修改函数定义了!  代码如下:  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()的代码完全不用修改!

代码如下:  #-*- 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于是提供了一个语法糖来降低字符输入量。

代码如下:  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的频率也非常低。  代码如下:  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:  代码如下:  @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,如果你希望使用反射,可能会导致意外的结果。这个装饰器可以解决这个问题,它能将装饰过的函数的特殊属性保留。

代码如下:  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__其中一个的类加上其他的比较方法,这是一个类装饰器。如果觉得不好理解,不妨仔细看看这个装饰器的源代码:

代码如下:  def total_ordering(cls):  """Class decorator that fills in missing

ordering methods"""  convert = {  '__lt__': [('__gt__', lambda self, other:

other < self),  ('__le__', lambda self, other: not other <

self),  ('__ge__', lambda self, other: not self < other)],  '__le__':

[('__ge__', lambda self, other: other <= self),  ('__lt__', lambda self,

other: not other <= self),  ('__gt__', lambda self, other: not self <=

other)],  '__gt__': [('__lt__', lambda self, other: other >

self),  ('__ge__', lambda self, other: not other > self),  ('__le__', lambda

self, other: not self > other)],  '__ge__': [('__le__', lambda self, other:

other >= self),  ('__gt__', lambda self, other: not other >=

self),  ('__lt__', lambda self, other: not self >= other)]  }  roots =

set(dir(cls)) & set(convert)  if not roots:  raise ValueError('must define

at least one ordering operation: < > <= >=')  root = max(roots) #

prefer __lt__ to __le__ to __gt__ to __ge__  for opname, opfunc in

convert[root]:  if opname not in roots:  opfunc.__name__ =

opname  opfunc.__doc__ = getattr(int, opname).__doc__  setattr(cls, opname,

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

python安装第三方库-Python安装第三方库的3种方法相关推荐

  1. Python炫技操作:花式导包的八种方法

    点击上方"Python爬虫与数据挖掘",进行关注 回复"书籍"即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 五岳寻仙不辞远,一身好入名山游. ...

  2. Python爬虫入门之爬虫解析提取数据的四种方法

    本文主要介绍了Python爬虫入门之爬虫解析提取数据的四种方法,通过具体的内容向大家展现,希望对大家Python爬虫的学习有所帮助. 基础爬虫的固定模式 笔者这里所谈的基础爬虫,指的是不需要处理像异步 ...

  3. Python中记住过去(模型状态)的五种方法

    在Python中记住过去(模型状态)的五种方法 从封闭函数和迭代器到状态机Python库 有人说... "那些不能记住过去的人,注定要重复它".G. Santayana, 1905 ...

  4. python脚本判断一个数是否为素数的几种方法

    质数又称素数.指在一个大于1的自然数中,除了1和此整数自身外,不能被其他自然数整除的数.素数在数论中有着很重要的地位.比1大但不是素数的数称为合数.1和0既非素数也非合数.质数是与合数相对立的两个概念 ...

  5. python中none算变量吗_在python中对变量判断是否为None的三种方法总结

    三种主要的写法有: 第一种:if X is None; 第二种:if not X: 当X为None,  False, 空字符串"", 0, 空列表[], 空字典{}, 空元组()这 ...

  6. python中判断一个数是否为素数_【转载】Python脚本判断一个数是否为素数的几种方法...

    质数又称素数.指在一个大于1的自然数中,除了1和此整数自身外,不能被其他自然数整除的数.素数在数论中有着很重要的地位.比1大但不是素数的数称为合数.1和0既非素数也非合数.质数是与合数相对立的两个概念 ...

  7. mysql数据库最后一步卡住了_[数据库]解决MySQL安装到最后一步未响应的三种方法...

    [数据库]解决MySQL安装到最后一步未响应的三种方法 0 2018-07-13 01:01:27 这种情况一般是你以前安装过MySQL数据库服务项被占用了. 解决方法: 方法一:安装MySQL的时候 ...

  8. python地图gps轨迹可视化_GPS轨迹可视化的三种方法

    Contents: 1.GIS软件 2.js在线工具或api 3.万能的Python 做ML的时候,清洗数据也好,特征工程也好,当遇到时空数据,或者要建立LBS特征时,难免需要对坐标维度做可视化打点, ...

  9. Python的pip怎样更新到最新版本:两种方法!

    Python的pip怎样更新到最新版本:两种方法! 方法一: 在管理员模式的控制台里输入下面这行命令 python -m pip install --upgrade pip 方法二: Anaconda ...

  10. #Python# 二维数组的定义、使用的几种方法

    #Python# 二维数组的定义.使用的几种方法 通常的困扰 1.先介绍最简单的一种方式 2.再介绍最常见的一种方式 3.最后介绍最暴力直观的一种方式 通常的困扰 之前对Python里面创建.使用二维 ...

最新文章

  1. synchronized的四种用法
  2. opencv 获取一个目录下子目录_OpenCV系列 --- OpenCV4.01配置VS2015
  3. syslog数据接收并处理
  4. access里面的表达式运用_Access表达式解析
  5. 关于一致/非一致代码段与TSS 关系的个人看法
  6. python网络编程初级
  7. LA 4794 - Sharing Chocolate dp
  8. 编译器预编译与变量提升
  9. Oracle和MySQL语法区别
  10. Linux 加密压缩与解压
  11. CodeBlocks配置openGL教程
  12. rust执行cmd命令隐藏窗口
  13. 2018 最新 cnki账号 中国知网账号 帐号 免费入口 用户名 密码 万方 维普
  14. 时间复杂度比较以及额外空间复杂度O(1)
  15. MSF(Metasploit)渗透测试---黑客工具使用指南
  16. Ubuntu下 vim安装失败的解决方法 以及安装vim
  17. 《数据结构(C语言版)》严巍敏课件~第七章:图
  18. 【云原生】设备云之前端可视化编程基础
  19. 【数据结构与算法】普里姆算法的介绍和修路问题程序实现
  20. 武钢四中2021高考成绩查询,长虹中学2019高考喜报

热门文章

  1. 腾讯的模板引擎---artTemplate
  2. #include 和 #include 的区别
  3. Tiny210编译和烧写u-boot步骤
  4. UVa 10820 (打表、欧拉函数) Send a Table
  5. Boosting(提升方法)之XGBoost
  6. JavaWeb学习笔记28--Filter高级开发
  7. LINUX下GDB反汇编和调试
  8. 从 Eclipse 迁移至 Android Studio
  9. jquery为图片添加事件
  10. 跪求AI编程语言--纯中文代码