zoukankan      html  css  js  c++  java
  • 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)
    ’‘’
    
  • 相关阅读:
    数据清洗
    JAVA多线程三种实现方式
    QT-4.8.6 编译配置过程
    qt 编译问题总结
    [转载]tslib1.4与Qt4.8.6的交叉编译与移植
    STC12C5A60S2 @ 22.0184Mhz 精确延时
    STC12C5A60S2 双串口通信
    C# Bitmap 复制
    TextMate2 最新版下载及源码编译过程
    mac系统 PHP Nginx环境变量修改
  • 原文地址:https://www.cnblogs.com/liujitao79/p/8532764.html
Copyright © 2011-2022 走看看