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?

  • 相关阅读:
    Python 通过最低位判断数字是偶数还是奇数
    C语言 windows下Ansi和UTF-8编码格式的转换
    C语言 Ubuntu系统 UTF-8 文字处理
    C语言 使用char字符实现汉字处理
    C# GUI应用 实现 2048游戏
    Docker部署Minio
    Ubuntu18.04开启root
    Ubuntu18.04安装Docker
    docker安装mysql
    idea启动项目端口被占用
  • 原文地址:https://www.cnblogs.com/gattaca/p/7290296.html
Copyright © 2011-2022 走看看