问题:python
经过高阶段函数返回一个新函数数据库
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() #10
python内置的@语法就是为了简化装饰器app
使用 decorator 用Python提供的 @ 语法,这样能够避免手动编写 f = decorate(f) 这样的代码。函数
相似上述的方法2post
装饰器的做用性能
能够极大的简化代码,避免每一个函数编写重复性代码spa
举例:日志
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
对于不是一个参数的函数,须要修改:code
要让 @log 自适应任何参数定义的函数,能够利用Python的 *args 和 **kw,保证任意个数的参数老是能正常调用:orm
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)
带参数的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
@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),所以,没法得到原函数的原始参数信息。
当一个函数有不少参数时,调用者就须要提供多个参数。若是减小参数个数,就能够简化调用者的负担。
functools.partial就是帮助咱们建立一个偏函数的,不须要咱们本身定义int2(),能够直接使用下面的代码建立一个新的函数int2:
>>> import functools >>> int2 = functools.partial(int, base=2) >>> int2('1000000') 64 >>> int2('1010101') 85
举例:在sorted这个高阶函数中传入自定义排序函数就能够实现忽略大小写排序。
import functools
sorted_ignore_case = functools.partial(sorted,key=str.lower) print sorted_ignore_case(['bob', 'about', 'Zoo', 'Credit'])