Python-An error in the use of adorners

Source: Internet
Author: User

The basic concept of adorners

As you know, adorners are a well-known design pattern that is often used in AOP (aspect-oriented programming) scenarios, with more classic insert logs, performance tests, transaction processing, Web权限校验 and Cache so on.

The Python language itself provides the adorner syntax (@), and the typical adorner implementation is as follows:

    @function_wrapper    def function():       pass

@ is actually python2.4 's proposed syntax sugar, there is another equivalent implementation for the previous version of python2.4:

    def function():        pass    function = function_wrapper(function)
Two kinds of implementations of adorners

Function Wrapper-Classic implementation

    def function_wrapper(wrapped):        def _wrapper(*args, **kwargs):            return wrapped(*args, **kwargs)        return _wrapper     @function_wrapper    def function():        pass

Class wrapper-Easy to understand

    class function_wrapper(object):        def __init__(self, wrapped):            self.wrapped = wrapped        def __call__(self, *args, **kwargs):            return self.wrapped(*args, **kwargs)    @function_wrapper    def function():        pass
Functions (function) introspection

When we talk about a function, we usually want the properties of the function to be clearly defined, such as and, as described in its __name__ documentation __doc__ .

When you apply adorners to a function, the properties of the function change, but this is not what we expect.

    def function_wrapper(wrapped):        def _wrapper(*args, **kwargs):            return wrapped(*args, **kwargs)        return _wrapper     @function_wrapper    def function():        pass     >>> print(function.__name__)    _wrapper

The Python standard library functools.wraps() is provided to solve this problem.

 import  functools def  function_wrapper   (wrapped) :   @functools. Wraps (wrapped)  Span class= "hljs-function" >def  _wrapper   (*args, **kwargs) :  return  wrapped (*args, * *     Kwargs) return  _wrapper  @function_wrapper  def  function   () :  pass  >>> print (function.__name __) function  

However, when we want to get the parameter ( argument ) or source code () of the wrapped function source code , we also can't get the result we want.

    ImportInspect def function_wrapper(wrapped):...@function_wrapper     def function(arg1, arg2): Pass>>> Print (Inspect.getargspec (function)) Argspec (args=[], varargs=' args ', keywords=' Kwargs ', defaults=None) >>> Print (Inspect.getsource (function))@functools. Wraps (wrapped)         def _wrapper(*args, **kwargs):            returnWrapped (*args, **kwargs)
Wrapper class method (@classmethod)

When the wrapper ( @function_wrapper ) is applied @classmethod , the following exception will be thrown:

     class class(Object):        @function_wrapper        @classmethod         def cmethod(CLS):            PassTraceback (most recent): File"<stdin>", line1,inch<module> File"<stdin>", line3,inchClass File"<stdin>", line2,inchWrapper File".../functools.py", line -,inchUpdate_wrapper setattr (Wrapper, attr, GetAttr (wrapped, attr)) Attributeerror:' Classmethod 'object has no attribute' __module__ '

Because @classmethod when implemented, functools.update_wrapper some of the required properties are missing. This is the functools.update_wrapper bug,3.2 version in Python2 that has been fixed, refer to http://bugs.python.org/issue3445.

However, under Python3, another problem arose:

     class class(Object):        @function_wrapper        @classmethod         def cmethod(CLS):            Pass>>> Class.cmethod () Traceback (most recent call last): File"classmethod.py", line the,inch<module> Class.cmethod () File"classmethod.py", line6,inch_wrapperreturnWrapped (*args, **kwargs) TypeError:' Classmethod 'Object is  notCallable

This is because the wrapper determines that the packaged function ( @classmethod ) can be called directly, but the fact is not necessarily the case. The wrapped function may actually be a descriptor ( descriptor ), meaning that the function (descriptor) must be properly bound to an instance in order to make it callable. For the definition of descriptors, refer to https://docs.python.org/2/howto/descriptor.html.

Summary-simplicity does not mean that the right

Although the methods used by people to implement adorners are usually simple, this does not mean that they must be correct and always work correctly.

As we have seen above, we functools.wraps() can solve __name__ __doc__ the problem, but it is useless to get the parameters (argument) or source code () of the function source code .

The above problem, WRAPT can help to solve, detailed usage can refer to its official document: http://wrapt.readthedocs.org

This article is compiled and collated by ONEAPM engineers. ONEAPM is the emerging leader in China's basic software industry, helping enterprise users and developers easily implement slow program code and real-time crawling of SQL statements. To read more technical articles, please visit the ONEAPM Official technology blog.

Python-An error in the use of adorners

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.