• Python decorator装饰器


    问题:

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

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

    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内置的@语法就是为了简化装饰器

    使用 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('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'])
  • 相关阅读:
    javahtml标签介绍
    腾讯课堂下载视频
    数据库
    eclipse将web项目部署到tomcat下
    c++ 枚举目录
    2022年,鉴历史,谋发展
    数字治理(软件信息化)与人性。 附:《全球数字治理白皮书》下载。
    iNeuOS工业互联网操作系统,顺利从NetCore3.1升级到Net6的过程汇报
    iNeuOS工业互联网操作系统下发命令给iNeuLink硬件网关,进一步修改设备参数和控制设备
    [免费下载应用]iNeuKernel.Ocr 图像数据识别与采集的产品化应用
  • 原文地址:https://www.cnblogs.com/dear_diary/p/6864091.html
Copyright © 2020-2023  润新知