问题:

  • 定义了一个新函数
  • 想在运行时动态增加功能
  • 又不想改动函数本身的代码

通过高阶段函数返回一个新函数

def f1(x):
return x*2 def new_fn(f): #装饰器函数
def fn(x):
print ('call ' + f.__name__ + '()')
return f(x)
return fn
#方法1
g1 = new_fn(f1)
print (g1(5))
#方法2
f1 = new_fn(f1) #f1的原始定义函数彻底被隐藏了
print (f1(5)) #输出:
#call f1()
#

装饰器

python内置的@语法就是为了简化装饰器

使用 decorator 用Python提供的 @ 语法,这样可以避免手动编写 f = decorate(f) 这样的代码。

类似上述的方法2

装饰器的作用

可以极大的简化代码,避免每个函数编写重复性代码

  • 打印日志:@log
  • 检测性能:@performance
  • 数据库事务:@transaction
  • URL路由:@post('/register')

python中编写无参数decorator

举例:

def log(f):
def fn(x):
print 'call ' + f.__name__ + '()...'
return f(x)
return fn @log
def factorial(n):
return reduce(lambda x,y: x*y, range(1, n+1))
print factorial(10) #结果
call factorial()...
3628800

对于不是一个参数的函数,需要修改:

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

def log(f):
def fn(*args, **kw):
print 'call ' + f.__name__ + '()...'
return f(*args, **kw)
return fn
@log
def add(x, y):
return x + y
print add(1, 2)

python中编写带参数decorator

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

def log(prefix):
def log_decorator(f):#标准decorator
def wrapper(*args, **kw):
print '[%s] %s()...' % (prefix, f.__name__)
return f(*args, **kw)
return wrapper
return log_decorator #返回log @log('DEBUG')
def test():
pass
print test()
#执行结果
[DEBUG] test()...
None

python中完善decorator

@decorator可以动态实现函数功能的增加,但是,经过@decorator“改造”后的函数,和原函数相比,有所不同:

def f1(x):
pass
print f1.__name__ #输出
f1
def log(f):
def wrapper(*args, **kw):
print 'call...'
return f(*args, **kw)
return wrapper
@log
def f2(x):
pass
print f2.__name__ #输出
wrapper

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

方法1:

def log(f):
def wrapper(*args, **kw):
print 'call...'
return f(*args, **kw)
wrapper.__name__ = f.__name__
wrapper.__doc__ = f.__doc__
return wrapper

方法2:Python内置的functools可以用来自动化完成这个“复制”的任务(推荐使用)

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

最后需要指出,由于我们把原函数签名改成了(*args, **kw),因此,无法获得原函数的原始参数信息。

python中偏函数

当一个函数有很多参数时,调用者就需要提供多个参数。如果减少参数个数,就可以简化调用者的负担。

functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2:

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('')
64
>>> int2('')
85

举例:在sorted这个高阶函数中传入自定义排序函数就可以实现忽略大小写排序。

import functools
sorted_ignore_case = functools.partial(sorted,key=str.lower)
print sorted_ignore_case(['bob', 'about', 'Zoo', 'Credit'])

Python decorator装饰器的更多相关文章

  1. python decorator 装饰器

    python装饰器是个对嵌套函数的语法糖 作用是在函数调用方法不变的情况下,将函数包装成另一个函数来使用 ---- import time def sum1(): sum = 1 + 2 print ...

  2. Python进阶之decorator装饰器

    decorator装饰器 .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB&quo ...

  3. 谈谈Python中的decorator装饰器,如何更优雅的重用代码

    众所周知,Python本身有很多优雅的语法,让你能用一行代码写出其他语言很多行代码才能做的事情,比如: 最常用的迭代(eg: for i in range(1,10)), 列表生成式(eg: [ x* ...

  4. python之装饰器(decorator)

    python的装饰器如果用得好,那是大神,用的不好最好别用... 装饰器(decorator)主要包含俩大属性: 1.不能改变原有函数的调用方式 2.不能改变原有函数的代码 第一个表示,我不需要改变原 ...

  5. Python的程序结构[8] -> 装饰器/Decorator -> 装饰器浅析

    装饰器 / Decorator 目录 关于闭包 装饰器的本质 语法糖 装饰器传入参数 1 关于闭包 / About Closure 装饰器其本质是一个闭包函数,为此首先理解闭包的含义. 闭包(Clos ...

  6. Python各式装饰器

    Python装饰器,分两部分,一是装饰器本身的定义,一是被装饰器对象的定义. 一.函数式装饰器:装饰器本身是一个函数. 1.装饰函数:被装饰对象是一个函数 [1]装饰器无参数: a.被装饰对象无参数: ...

  7. python基础——装饰器

    python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...

  8. 【转】详解Python的装饰器

    原文链接:http://python.jobbole.com/86717/ Python中的装饰器是你进入Python大门的一道坎,不管你跨不跨过去它都在那里. 为什么需要装饰器 我们假设你的程序实现 ...

  9. python 基础——装饰器

    python 的装饰器,其实用到了以下几个语言特点: 1. 一切皆对象 2. 函数可以嵌套定义 3. 闭包,可以延长变量作用域 4. *args 和 **kwargs 可变参数 第1点,一切皆对象,包 ...

随机推荐

  1. Cannot enlarge string buffer containing XX bytes by XX more bytes

    在ELK的数据库报警系统中,发现有台机器报出了下面的错误: 2018-12-04 18:55:26.842 CST,"XXX","XXX",21106,&quo ...

  2. 详细MATLAB 中BP神经网络算法的实现

    MATLAB 中BP神经网络算法的实现 BP神经网络算法提供了一种普遍并且实用的方法从样例中学习值为实数.离散值或者向量的函数,这里就简单介绍一下如何用MATLAB编程实现该算法. 具体步骤   这里 ...

  3. 疯狂Android讲义

    1 Android应用和开发环境2 Android应用的界面编程3 Android的事件处理4 Activity Fragment5 Intent IntentFilter6 Android应用的资源 ...

  4. webpack 多页面|入口支持和公共组件单独打包--转载

    转载自:http://www.jb51.net/article/117490.htm 本篇主要介绍:如何自动构建入口文件,并生成对应的output:公共js库如何单独打包. 多入口文件,自动扫描入口. ...

  5. 转:NSString / NSData / char* 类型之间的转换

    1. NSString转化为UNICODE String: (NSString*)fname = @“Test”; char fnameStr[10]; memcpy(fnameStr, [fname ...

  6. 数据结构编程实验——chapter10-应用经典二叉树编程

    二叉树不仅结构简单.节省内存,更重要是是这种结构有利于对数据的二分处理.之前我们提过,在二叉树的基础上能够派生很多经典的数据结构,也是下面我们将进行讨论的知识点: (1)   提高数据查找效率的二叉排 ...

  7. NGINX配置PHP解析

    <?php phpinfo(); ?> location ~ \.php$ { root html; fastcgi_pass ; fastcgi_index index.php; fas ...

  8. charles抓包详解http 与 https

    包工具多种多样,比较好使的还是Charles和Fiddler,下面就简单的介绍下HTTPS的相关原理并以Charles为例来介绍下如何抓取HTTPS协议的包 1.下载charles 可以去charle ...

  9. MySQL数据库远程连接很慢的解决方案

    在开发机器上链接mysql数据库很慢,但是在数据库服务器上直接链接数据库很快.猜测应该是远程链接解析的问题,在查询MySQL相关文档和网络搜索后,发现了一个配置似乎可以解决这样的问题,就是在MySQL ...

  10. [转载]如何做到 jQuery-free?

    http://www.ruanyifeng.com/blog/2013/05/jquery-free.html jQuery是现在最流行的JavaScript工具库. 据统计,目前全世界57.3%的网 ...