zoukankan      html  css  js  c++  java
  • python decorator

    decorator(装饰器)绝对是Python学习道路上的一个拦路虎。想要理解它,先看两个概念。

    nested function(内嵌函数)

    def helper(num):
        def is_even(arg):
            return arg % 2 == 0
        if is_even(num):
            print(num, 'is even')
        else:
            print(num, 'is odd')

    类似于函数局部变量,内嵌函数就是函数的局部函数。

    Python的内嵌函数有个特点,它可以访问自身作用域外围的变量。

    def helper(num):
        def is_even():
            return num % 2 == 0
        if is_even():
            print(num, 'is even')
        else:
            print(num, 'is odd')

    内嵌函数is_even可以直接访问外围参数num。

    函数可以作为返回值

    def helper(type):
        def helper_lower(arg):
            return arg.lower()
        def helper_upper(arg):
            return arg.upper()
        if type == 'lower':
            return helper_lower
        else:
            return helper_upper
    
    mylower = helper('lower')
    print(mylower)
    print(mylower('HELLO WORLD'))
    
    myupper = helper('upper')
    print(myupper)
    print(myupper('hello world'))

    <function helper.<locals>.helper_lower at 0x106aee598>
    hello world
    <function helper.<locals>.helper_upper at 0x106aee730>
    HELLO WORLD

    现在回到装饰器。

    装饰器的作用是,在不改变函数原有实现的基础上,给函数增加新的功能。

    举个例子:

    def decorator(func):
        print('before the function runs...')
        func()
        print('after the function runs...')
        
    def hello():
        print('hello, i am foo')

    现在执行decorator(hello),输出如下:

    before the function runs...
    hello, i am foo
    after the function runs...

     

    但是有个问题,为了这个新功能,用户需要把所有调用hello的地方换成decorator(hello)。

    可以通过返回内嵌函数的方式解决:

    def decorator(func):
        def wrapper():
            print('before the function runs...')
            func()
            print('after the function runs...')
        return wrapper
    
    def hello():
        print('hello, i am foo')
        
    hello = decorator(hello)
    hello()

    如果原先的函数hello有参数怎么办呢?

    def decorator(func):
        def wrapper(name):
            print('before the function runs...')
            func(name)
            print('after the function runs...')
        return wrapper
    
    def hello(name):
        print('hello, i am', name)
        
    hello = decorator(hello)
    hello('logan')

    参数传递细节

    hello('logan')

    decorator(hello)('logan')

    wrapper('logan')

    通用版本的decorator如下:

    def decorator(func):
        def wrapper(*args, **kw):
            print('before the function runs...')
            func(*args, **kw)
            print('after the function runs...')
        return wrapper

    python为了简化hello = decorator(hello),使用了@符号。

    def decorator(func):
        def wrapper(*args, **kw):
            print('before the function runs...')
            func(*args, **kw)
            print('after the function runs...')
        return wrapper
    
    @decorator
    def hello(name):
        print('hello, i am', name)
    
    hello('logan')

    另一种实现decorator的方法是functools.wraps

    import functools
    
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('before the function runs...')
            func(*args, **kw)
            print('after the function runs...')
        return wrapper
    
    @decorator
    def hello(name):
        print('hello, i am', name)
    
    hello('logan')

    参考资料:

    How to make a chain of function decorators?

  • 相关阅读:
    Android开发之适配器-ListView适配器的重复数据
    Android开发之TextView的下划线添加
    Android 自定义View修炼-Android开发之自定义View开发及实例详解
    Android 开发之自定义Dialog及UI的实现
    Android开发之ContentProvider(内容提供者)
    XC文件管理器(Android应用)
    高效 告别996,开启java高效编程之门 4-1普通码农与风骚码农资源关闭PK
    高效 告别996,开启java高效编程之门 4-2垃圾回收与物理资源释放
    高效 告别996,开启java高效编程之门 3-29实战案例五:排序
    高效 告别996,开启java高效编程之门 3-28实战案例四:分组
  • 原文地址:https://www.cnblogs.com/gattaca/p/7290296.html
Copyright © 2011-2022 走看看