python闭包&装饰器&偏函数

什么是闭包?

首先还得从基本概念说起,什么是闭包呢?来看下维基上的解释:
在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。

上面提到了两个关键的地方: 自由变量和函数, 这两个关键稍后再说。还是得在赘述下“闭包”的意思,望文知意,可以形象的把它理解为一个封闭的包裹,这个包裹就是一个函数,当然还有函数内部对应的逻辑,包裹里面的东西就是自由变量,自由变量可以在随着包裹到处游荡。当然还得有个前提,这个包裹是被创建出来的。

在通过Python的语言介绍一下,一个闭包就是你调用了一个函数A,这个函数A返回了一个函数B给你。这个返回的函数B就叫做闭包。你在调用函数A的时候传递的参数就是自由变量。

例子

def func(name):
    def inner_func(age):
        print 'name:', name, 'age:', age
    return inner_func

bb = func('ken')
bb(26)

#  name:  ken age:  26

这里面调用func的时候就产生了一个闭包——inner_func,并且该闭包持有自由变量——name,因此这也意味着,当函数func的生命周期结束之后,name这个变量依然存在,因为它被闭包引用了,所以不会被回收。

另外再说一点,闭包并不是Python中特有的概念,所有把函数做为一等公民的语言均有闭包的概念。不过像Java这样以class为一等公民的语言中也可以使用闭包,只是它得用类或接口来实现

装饰器

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

f = now   # f指向函数对象now
f()           # 调用输出 2015-3-25

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

>>> f.__name__
'now'

>>> now.__name__
'now'

>>> now
<function now at 0x7f1cbf5d7510>

>>> f
<function now at 0x7f1cbf5d7510>

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

def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper
@log
def now():
    print('2015-3-25')
>>> now()
call now():
2015-3-25

更复杂的装饰器,比如装饰器需要调用参数

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

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

>>> now.__name__
'wrapper'

还差最后一步。因为我们讲了函数也是对象,它有__name__等属性,但你去看经过decorator装饰之后的函数,它们的__name__已经从原来的'now'变成了'wrapper',这是问题,应该返回now才对。

最终版本

import functools

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

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


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

now.__name__
'now'
'''

带参数

import functools

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

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

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

now.__name__
'now'
'''

偏函数

functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。
创建偏函数时,实际上可以接收函数对象、*args和**kw这3个参数

int2 = functools.partial(int, base=2)

int2('10010')

‘’‘相当于
kw = { 'base': 2 }
int('10010', **kw)
’‘’
原文地址:https://www.cnblogs.com/liujitao79/p/8532764.html