由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。

>>> def now():
... print('2015-3-25')
...
>>> f = now
>>> f()
2015-3-25

函数对象有一个__name__属性,可以拿到函数的名字:

>>> now.__name__
'now'
>>> f.__name__
'now'

现在,假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。

本质上,decorator就是一个返回函数的高阶函数。如果你觉得理解的还不够透彻可以去小编的Python技术球球qun:278136312 qun里面有我总结的比较详细的Python全面的视频教程,需要的自己去公告里面下载学,希望对你有帮助。所以,我们要定义一个能打印日志的decorator,可以定义如下:

def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper

观察上面的log,因为它是一个decorator,所以接受一个函数作为参数,并返回一个函数。我们要借助Python的@语法,把decorator置于函数的定义处:

@log
def now():
print('2015-3-25')

调用now()函数,不仅会运行now()函数本身,还会在运行now()函数前打印一行日志:

>>> now()
call now():
2015-3-25

@log放到now()函数的定义处,相当于执行了语句:

now = log(now)

由于log()是一个decorator,返回一个函数,所以,原来的now()函数仍然存在,只是现在同名的now变量指向了新的函数,于是调用now()将执行新函数,即在log()函数中返回的wrapper()函数。

wrapper()函数的参数定义是(*args, **kw),因此,wrapper()函数可以接受任意参数的调用。在wrapper()函数内,首先打印日志,再紧接着调用原始函数。

如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本:

def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator

这个3层嵌套的decorator用法如下:

@log('execute')
def now():
print('2015-3-25')

执行结果如下:

>>> now()
execute now():
2015-3-25

和两层嵌套的decorator相比,3层嵌套的效果是这样的:

>>> now = log('execute')(now)

我们来剖析上面的语句,首先执行log('execute'),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。

以上两种decorator的定义都没有问题,但还差最后一步。因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper'

>>> now.__name__
'wrapper'

因为返回的那个wrapper()函数名字就是'wrapper',所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。

Python装饰器使用规范案例详解的更多相关文章

  1. python装饰器(docorator)详解

    引言: 装饰器是python面向对象编程三大器之一,另外两个迭代器.生成器只是我现在还没有遇到必须使用的场景,等确实需要用到的时候,在补充资料:装饰器在某些场景真的是必要的,比如定义了一个类或者一个函 ...

  2. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

     1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...

  3. Python函数装饰器原理与用法详解《摘》

    本文实例讲述了Python函数装饰器原理与用法.分享给大家供大家参考,具体如下: 装饰器本质上是一个函数,该函数用来处理其他函数,它可以让其他函数在不需要修改代码的前提下增加额外的功能,装饰器的返回值 ...

  4. python装饰器的应用案例

    目录 一.过程编程 二.面向装饰器和函数的编程 三.二的加强版 一.过程编程 (一)需求:打印菱形 1.空格.*号组成的菱形 2.输入菱形上半部分的行数即可打印 3.支持循环输入 (二)代码 from ...

  5. 第7.18节 案例详解:Python类中装饰器@staticmethod定义的静态方法

    第7.18节 案例详解:Python类中装饰器@staticmethod定义的静态方法 上节介绍了Python中类的静态方法,本节将结合案例详细说明相关内容. 一.    案例说明 本节定义了类Sta ...

  6. 第7.27节 Python案例详解: @property装饰器定义属性访问方法getter、setter、deleter

    上节详细介绍了利用@property装饰器定义属性的语法,本节通过具体案例来进一步说明. 一.    案例说明 本节的案例是定义Rectangle(长方形)类,为了说明问题,除构造函数外,其他方法都只 ...

  7. Python装饰器详解

    python中的装饰器是一个用得非常多的东西,我们可以把一些特定的方法.通用的方法写成一个个装饰器,这就为调用这些方法提供一个非常大的便利,如此提高我们代码的可读性以及简洁性,以及可扩展性. 在学习p ...

  8. 第7.20节 案例详解:Python抽象类之真实子类

    第7.20节 案例详解:Python抽象类之真实子类 上节介绍了Python抽象基类相关概念,并介绍了抽象基类实现真实子类的步骤和语法,本节结合一个案例进一步详细介绍. 一.    案例说明 本节定义 ...

  9. 第7.16节 案例详解:Python中classmethod定义的类方法

    第7.16节  案例详解:Python中classmethod定义的类方法 上节介绍了类方法定义的语法以及各种使用的场景,本节结合上节的知识具体举例说明相关内容. 一.    案例说明 本节定义的一个 ...

随机推荐

  1. 【Java】国内maven私服

    <mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> & ...

  2. BIO,NIO,AIO的理解

    BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善. NIO: ...

  3. c# string.format 的简写 $

    var name = "huchao"; var info = $"你是谁,我叫:{name}"; Console.Write(info); Console.R ...

  4. 使用compiz出现奔溃的一些应急办法

    Linux Mint 17.1 CompizConfig is also installed by default so you can configure every aspect of Compi ...

  5. git从安装到应用的学习

    本文内容是对廖雪峰老师Git教程做的笔记,外加一些自己的学习心得,还抱着学以致用的心态来实践一番 Git学习笔记 分布式版本控制与集中式版本控制的最大区别 集中式的版本控制,本地没有历史记录,完整的仓 ...

  6. 《Head First 设计模式》之适配器模式与外观模式

    适配器模式(Adapter) 适配器(adapter-pattern):将一个类的接口,转换成客户期望的另一个接口.适配器让原来接口不兼容的类可以合作无间.两种形式: 对象适配器(组合) 类适配器(多 ...

  7. Git 常用基本命令汇总

    安装git yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel yum install -y gi ...

  8. uLua学习之调用Lua函数(五)

    前言 在我开始这个系列的第一篇文章中,我就提到了Lua脚本用来实现宿主脚本的配置性和扩展性.上节说到的调用外部Lua脚本就对应了它的两大特性之一的配置性,那么另一大特性如何来体现呢?这就要说我们今天的 ...

  9. MySQL-数据类型及选择

    一.数据类型 详见:http://www.runoob.com/mysql/mysql-data-types.html 二.类型选择 整形>date,time>enum,char>v ...

  10. 索引是否也能提高UPDATE,DELETE,INSERT速度 解释

    insert 不会提高,insert 用不到索引,只会增加维护索引的时间. update ,更新索引列不会提高,少量更新非索引列,会有提高 : 更新索引列,索引要重新维护,更新非索引列,倒是没什么影响 ...