zoukankan      html  css  js  c++  java
  • Decorators and Wrappers in Python

    python代码一贯以优雅,简洁著称,而有时侯反而会让人难以理解,比如说wrapper(或者说decorator),这种方式提高了代码的可重用性,使用起来更简洁方便。

    举个例子,比如WebApp常用的处理请求的Handler。

    def show_page(request):
        # do something
        return response

    有些时候,如果请求是POST方式发送过来的,可能你需要检查用户名和密码的合法性。这个时候,你不得不修改以上函数来做必要的认证处理:

    def show_page(request):
        authenticator.authenticate(request)
        # do stuff
        return response

    但是这样做后,你发现你不想将代码植入到已经编好的功能中,因为那样做很stupid,如果每个需要认证的的地方都这样做,许多编号的handler都将改写。这似乎违背了代码的reusable。再者,从功能模块角度来看,认证似乎是一个辅助功能,不应该集成到Handler中。于是乎,使用decorators(或 wrappers)是一个不错的选择:

    @authenticate
    def show_page(request):
        # do stuff
        return response

    一个简单的authentiate如下:

    def authenticate(func):
        def authenticate_and_call(*args, **kwargs):
            if not Account.is_authentic(request): 
                raise Exception('Authentication Failed.')
            return func(*args, **kwargs)
        return authenticate_and_call

    经过@authenticate处理后的show_page(request)函数等价于如下:

    show_page = authenticate(show_page)

    从上面的函数也可直观的看出为什么decorator又叫做wrapper了,很直观的类似包装了一层东西一样,升级为2.0版本。

    python是函数式编程语言,函数可以作为参数传递或返回值返回。对于authenticate函数,在传入show_page后返回一个函数authenticate_and_call,也就是说show_page被重新指向了authenticate_and_call。

    show_page = authenticate(*args, **kwargs)

    这样一来,show_page加入了新的功能,完成了包装。他还是可以接收request参数,因为其参数是(*args, **kwargs)。

    此处顺便提一下python的 *args参数,看下面例子:

    def func1(x, y, z):
        print x
        print y 
        print z                 
    
    def func2(*args):
        # Convert args tuple to a list so we can modify it
        args = list(args)
        args[0] = 'Hello'
        args[1] = 'awesome'
        func1(*args)
    
    func2('Goodbye', 'cruel', 'world!')
    # Will print
    # > Hello
    # > awesome
    # > world!

    python中有很多库函数和自带函数参数中都包含*args, **kwargs,传递过来时就像一个"pack",而对于接收的函数来说可以"unpack"这些参数,做一些处理,例如:

    1. validate arguments before passing them on
    2. set defaults for positional arguments
    3. create adaptors for different pieces of code / libraries
    4. modify arguments depending on context
    5. log calls to methods
    6. write better and more resilient wrapper

    将参数定义为“任意”的方式在decorator中很常用。

    参考资料:

    http://hangar.herokuapp.com/python/packing-unpacking-arguments

    http://hangar.runway7.net/python/decorators-and-wrappers

  • 相关阅读:
    关于工作中Git相关的总结
    浅谈MySQL的优化
    由内搜推送思考Kafka 的原理
    SOA和微服务架构
    Centos7.2 搭建Lamp服务器以及迁移WordPress个人博客详细过程
    MyISAM和InnoDB索引实现区别
    图解高内聚与低耦合
    图解Java常用数据结构(一)
    Java源码安全审查
    Java高并发之锁优化
  • 原文地址:https://www.cnblogs.com/vin-yuan/p/4812908.html
Copyright © 2011-2022 走看看