Some suggestions for using the Python adorner

Source: Internet
Author: User
Tags stdin wrapper python decorator in python

This article mainly introduces some suggestions for the Python decorator, which is an important knowledge in Python learning, and needs a friend to consult with

The basic concept of adorners

We all know that the adorner is a well-known design pattern, often used in AOP (aspect-oriented programming) scene, more classic has inserted log, performance testing, transaction processing, Web permissions check, cache and so on.

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

?

1 2 3 @function_wrapper def function (): Pass

@ is actually a syntactic sugar python2.4, which has another equivalent implementation for python2.4 previous versions:

?

1 2 3 4 def function (): Pass function = Function_wrapper (function)

Two kinds of realization of adorner

Function Wrapper-Classic implementation

?

1 2 3 4 5 6 7 8 def function_wrapper (wrapped): Def _wrapper (*args, **kwargs): Return wrapped (*args, **kwargs) return _wrapper @function_ Wrapper def function (): Pass

Class wrapper-Easy to understand

?

1 2 3 4 5 6 7 8 9 Class Function_wrapper (object): Def __init__ (self, wrapped): self.wrapped = wrapped def __call__ (self, *args, **kwargs): R Eturn self.wrapped (*args, **kwargs) @function_wrapper def function (): Pass

Functions (function) introspection

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

When you apply an adorner to a function, the properties of the function change, but that's not what we expect.

?

1 2 3 4 5 6 7 8 9 10 11 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 provides functools.wraps () to solve this problem.

?

1 2 3 4 5 6 7 8 9 10 11 12 13-14 Import Functools def function_wrapper (wrapped): @functools. Wraps (wrapped) def _wrapper (*args, **kwargs): Return wrapped (*args, **kwargs) return _wrapper @function_wrapper def function (): Pass >>> print (function.__name__) functio N

However, when we want to get the parameters (argument) of the wrapped function or source code, we don't get the results we want.

?

1 2 3 4 5 6 7 8 9 10 11 12 13-14 Import Inspect Def function_wrapper (wrapped): ... @function_wrapper def function (Arg1, arg2): Pass >>> Prin T (Inspect.getargspec (function)) Argspec (args=[], varargs= ' args ', keywords= ' Kwargs ', Defaults=none) >>> Print (Inspect.getsource (function)) @functools. Wraps (wrapped) def _wrapper (*args, **kwargs): Return Wrapped (*args, * * Kwargs)

Packing class method (@classmethod)

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

?

1 2 3 4 5 6 7 8 9 10 11 12-13 Class Class (Object): @function_wrapper @classmethod def cmethod (CLS): Pass Traceback (most recent called last): File < Stdin> ", line 1, in <module> file ' <stdin> ', line 3, in Class File ' <stdin> ', line 2, in wrapper file ".../functools.py", line, in Update_wrapper setattr (wrapper, attr, GetAttr (wrapped, attr)) Attributeerror: ' Classmeth Od ' object has no attribute ' __module__ '

Because @classmethod is implemented, some of the attributes required by Functools.update_wrapper are missing. This is the bug,3.2 version of Functools.update_wrapper in Python2 has been repaired, reference http://bugs.python.org/issue3445.

However, executing under Python3, another problem arises:

?

1 2 3 4 5 6 7 8 9 10 11 12-13 Class Class (Object): @function_wrapper @classmethod def cmethod (CLS): Pass >>> Class.cmethod () traceback (most Recent call last): File "classmethod.py", line, in <module> class.cmethod () file "classmethod.py", line 6, in _WR Apper return Wrapped (*args, **kwargs) TypeError: ' Classmethod ' object are not callable

This is because the wrapper determines that the wrapped function (@classmethod) can be invoked 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 to make it callable. For the definition of descriptors, you can refer to https://docs.python.org/2/howto/descriptor.html.

Summary-Simple doesn't mean right

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

As we have seen above, functools.wraps () can help us solve problems with __name__ and __doc__, but there is no way to get a function's arguments (argument) or source code.

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.