问题:

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

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

  1. def f1(x):
  2. return x*2
  3.  
  4. def new_fn(f): #装饰器函数
  5. def fn(x):
  6. print ('call ' + f.__name__ + '()')
  7. return f(x)
  8. return fn
  9. #方法1
  10. g1 = new_fn(f1)
  11. print (g1(5))
  12. #方法2
  13. f1 = new_fn(f1) #f1的原始定义函数彻底被隐藏了
  14. print (f1(5))
  15.  
  16. #输出:
  17. #call f1()
  18. #

装饰器

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

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

类似上述的方法2

装饰器的作用

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

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

python中编写无参数decorator

举例:

  1. def log(f):
  2. def fn(x):
  3. print 'call ' + f.__name__ + '()...'
  4. return f(x)
  5. return fn
  6.  
  7. @log
  8. def factorial(n):
  9. return reduce(lambda x,y: x*y, range(1, n+1))
  10. print factorial(10)
  11.  
  12. #结果
  13. call factorial()...
  14. 3628800

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

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

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

python中编写带参数decorator

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

  1. def log(prefix):
  2. def log_decorator(f):#标准decorator
  3. def wrapper(*args, **kw):
  4. print '[%s] %s()...' % (prefix, f.__name__)
  5. return f(*args, **kw)
  6. return wrapper
  7. return log_decorator #返回log
  8.  
  9. @log('DEBUG')
  10. def test():
  11. pass
  12. print test()
  1. #执行结果
  2. [DEBUG] test()...
  3. None

python中完善decorator

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

  1. def f1(x):
  2. pass
  3. print f1.__name__
  4.  
  5. #输出
  6. f1
  1. def log(f):
  2. def wrapper(*args, **kw):
  3. print 'call...'
  4. return f(*args, **kw)
  5. return wrapper
  6. @log
  7. def f2(x):
  8. pass
  9. print f2.__name__
  10.  
  11. #输出
  12. wrapper

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

方法1:

  1. def log(f):
  2. def wrapper(*args, **kw):
  3. print 'call...'
  4. return f(*args, **kw)
  5. wrapper.__name__ = f.__name__
  6. wrapper.__doc__ = f.__doc__
  7. return wrapper

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

  1. import functools
  2. def log(f):
  3. @functools.wraps(f) #
  4. def wrapper(*args, **kw):
  5. print 'call...'
  6. return f(*args, **kw)
  7. return wrapper

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

python中偏函数

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

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

  1. >>> import functools
  2. >>> int2 = functools.partial(int, base=2)
  3. >>> int2('')
  4. 64
  5. >>> int2('')
  6. 85

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

  1. import functools
  2. sorted_ignore_case = functools.partial(sorted,key=str.lower)
  3. 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. ORB原理与源码解析

    转载: http://blog.csdn.net/luoshixian099/article/details/48523267 CSDN-勿在浮沙筑高台 没有时间重新复制代码,只能一股脑的复制,所以代 ...

  2. 数据分析与展示---Matplotlib入门

    简介: 一:Matplotlib库的介绍 (一)简单使用 二:区域划分subplot 三:plot函数 四:pyplot的中文显示 (一)方法一:修改rcParams参数 (二)方法二(推荐),在有中 ...

  3. 机器学习算法整理(二)梯度下降求解逻辑回归 python实现

    逻辑回归(Logistic regression) 以下均为自己看视频做的笔记,自用,侵删! 还参考了:http://www.ai-start.com/ml2014/ 用梯度下降求解逻辑回归 Logi ...

  4. Visual Studio Code 教程之————入门篇

    Visual Studio代码是一个轻量级但功能强大的源代码编辑器,可在您的桌面上运行,适用于Windows,macOS和Linux.它内置对JavaScript,TypeScript和Node.js ...

  5. c#+js 使用formdata上传文件

    如果不是使用form表单submit的形式,我们可以手动通过formdata传值(针对文件上传等) 比如: <html> <head> <meta name=" ...

  6. 有用的JavaScript开发小建议

    这篇文章将向你分享一些不为人知的但很有用的JavaScript小建议,对那些刚涉及使用JavaScript编程语言的初级开发者应该有很大的帮助. 1. 用数组长度截取数组 我们都知道,对象都是通过使用 ...

  7. 发现IE 9的一个独有的小bug,并附解决方案

    在最近的项目中,解决了一些浏览器兼容方面的bug,这篇主要描述在IE 9在渲染值为auto的overflow-x属性时,所产生的专属bug及解决办法. 1.问题描述 在做一个收货地址管理静态页面的时候 ...

  8. Linuc学习3-输入和输出重定向

    已打开的文件描述符在fork和exec调用后保留下来,我们可以利用对进程这方面知识点的理解来改变程序的行为. 这个例子涉及一个过滤程序:它从标准输入读取数据,然后向标准输出写数据,同时在输入和输出之间 ...

  9. POJ 1128 Frame Stacking (拓扑排序)

    题目链接 Description Consider the following 5 picture frames placed on an 9 x 8 array. ........ ........ ...

  10. Django 创建第一个Project — Django学习(二)

    检查django If Django is installed, you should see the version of your installation. If it isn’t, you’l ...