Python decorator and Aspect-Oriented Programming

Source: Internet
Author: User
Tags python decorator

Let's discuss the decorator today. The decorator is a well-known design model and is often used in scenarios with cut-plane requirements. It is more classic in terms of log insertion, performance testing, and transaction processing. The decorator is an excellent design for solving such problems. With the decorator, we can extract a large number of identical codes irrelevant to the function itself and continue to reuse them. In summary, the purpose of the decorator is to add additional functions to existing objects. 1. decorator entry 1.1. How can I meet my requirements? The definition of the decorator is very abstract. Let's look at a small example.? 1234def foo (): print 'in foo () 'foo () This is a boring function. But suddenly there was a more boring person. We called him B Jun and said, "I want to see how long it took to execute this function. Okay, so we can do this :? 12345678 import timedef foo (): start = time. clock () print 'in foo () 'end = time. clock () print 'used: ', end-start foo () is good, and the function looks impeccable. But B suddenly didn't want to look at this function at the moment. He became more interested in another function named foo2. What should we do? If you copy the newly added code to foo2, this makes a big mistake ~ Isn't copying anything the most annoying! What if B continues to read other functions? 1.2. do you still remember to change the value of the token that remains unchanged? If a function is a first-class citizen in Python, we can consider redefining the timeit function and passing the reference of foo to it, then call foo in timeit and perform timing. In this way, we achieve the goal of not modifying the definition of foo. No matter how many functions B reads, we don't need to modify the function definition!? 123456789101112 import time def foo (): print 'in foo () 'def timeit (func): start = time. clock () func () end = time. clock () print 'used: ', end-start timeit (foo) Looks like there is no logic problem, everything is wonderful and works properly! ...... Wait, we seem to have modified the code for calling. Originally we called: foo () in this way and changed it to: timeit (foo ). In this case, if foo is called at N, You have to modify the code at N. Or even more extreme, consider the situation where the code called somewhere cannot be modified. For example, this function is used by someone else. 1.3. minimize changes! In this case, let's try to avoid modifying the called code. If you do not modify the called code, it means that calling foo () requires the effect of calling timeit (foo. We can think of assigning timeit to foo, but timeit seems to have a parameter ...... Try to unify the parameters! If timeit (foo) does not directly produce calling results, but returns a function consistent with the foo parameter list ...... It is easy to do. Assign the return value of timeit (foo) to foo. Then, the code that calls foo () does not need to be modified!? 123456789101112131415161718192021 #-*-coding: UTF-8-*-import time def foo (): print 'in foo () '# define a timer, pass in, return another method def timeit (func) with the timing function appended: # define an embedded packaging function and add the packaging def wrapper () of the timing function to the input function (): start = time. clock () func () end = time. clock () print 'used: ', end-start # return the wrapped function return wrapper foo = timeit (foo) foo (). In this way, a simple timer is ready! We only need to add foo = timeit (foo) before calling foo after defining foo to achieve the purpose of timing. This is the concept of the decorator, it looks like foo is decorated by timeit. In this example, the function requires timing when entering and exiting, which is called an Aspect. This Programming method is called Aspect-Oriented Programming ). Compared with the traditional top-down execution method, it seems that a logic is inserted horizontally in the function execution process. In a specific business area, a large amount of repeated code can be reduced. There are quite a few terms for Aspect-oriented programming. I will not introduce them more here. If you are interested, you can look for relevant materials. This example is only used for demonstration and does not take into account the situation that foo has parameters and has returned values. The task of perfecting it is handed over to you.) 2. python supports an additional 2.1. the code above seems to be no longer streamlined, and Python provides a syntax sugar to reduce the input of characters.? 123456789101112131415 import time def timeit (func): def wrapper (): start = time. clock () func () end = time. clock () print 'used: ', end-start return wrapper @ timeitdef foo (): print 'in foo ()' foo () focuses on the @ timeit of line 1, adding this line to the definition is equivalent to writing foo = timeit (foo). Do not think that @ has another magic. In addition to fewer character input, there is an additional benefit: It looks more decorative. 2.2. there are three built-in decorators, staticmethod, classmethod, and property. They are used to convert the instance methods defined in the class into static methods, class methods, and class attributes. Since functions can be defined in a module, static methods and class methods are not very useful unless you want to fully object-oriented programming. Attributes are not indispensable, and Java is also very moist without attributes. From my own Python experience, I have never used property, and the frequency of using staticmethod and classmethod is also very low.? 12345678910111213141516 class Rabbit (object): def _ init _ (self, name): self. _ name = name @ staticmethod def newRabbit (name): return Rabbit (name) @ classmethod def newRabbit2 (cls): return Rabbit ('') @ property def name (self ): return self. _ name the attribute defined here is a read-only attribute. If you need to be writable, You need to define another setter :? 123@name.setterdef name (self, name): self. _ name = name2.3. functools module provides two decorators. This module is added after Python 2.5. Generally, most users use a version later than this version. But my usual work environment is 2.4 T-T 2.3.1. wraps (wrapped [, assigned] [, updated]): This is a useful decoration. A friend who has read the previous reflection article should know that a function has several special attributes, such as the function name. After being decorated, the function name foo in the previous example will become the wrapper name of the packaging function, if you want to use reflection, unexpected results may occur. The decorator can solve this problem and retain the special attributes of the decorated functions.? 123456789101112131415161718 import timeimport functools def timeit (func): @ functools. wraps (func) def wrapper (): start = time. clock () func () end = time. clock () print 'used: ', end-start return wrapper @ timeitdef foo (): print 'in foo () 'foo () print foo. _ name _ first, pay attention to the 5th rows. If you comment this line, foo. _ name _ will be 'wrapper '. In addition, I believe you have noticed that this decorator has a parameter. In fact, there are two other optional parameters. Attribute names in assigned are replaced by values, while attribute names in updated are merged by update, you can obtain the default values by viewing the source code of functools. For this decorator, it is equivalent to wrapper = functools. wraps (func) (wrapper ). 2.3.2. total_ordering (cls): This decorator is useful for specific occasions, but it is added after Python 2.7. It serves to add other comparison methods to the classes that implement at least _ lt _, _ le _, _ gt _, and _ ge _., this is a class decorator. If you think it is hard to understand, take a closer look at the source code of the decorator :? 123456789101112131415161718192021222324252653 def total_ordering (cls): 54 "Class decorator that fills in missing ordering methods" 55 convert = {56 '_ lt __': [('_ gt _', lambda self, other: other <self), 57 ('_ le _', lambda self, other: not other <self), 58 ('_ ge _', lambda self, other: not self <other)], 59' _ le __': [('_ ge _', lambda self, other: other <= self), 60 ('_ lt _', lambda self, other: not other <= self), 61 ('_ gt _', lambda self, other: not self <= other)], 62 '_ gt __': [('_ lt _', lambda self, other: other> self), 63 ('_ ge _', lambda self, other: not other> self), 64 ('_ le _', lambda self, other: not self> other)], 65' _ ge __': [('_ le _', lambda self, other: other> = self), 66 ('_ gt _', lambda self, other: not other> = self), 67 ('_ lt _', lambda self, other: not self> = other)] 68} 69 roots = set (dir (cls) & set (convert) 70 if not roots: 71 raise ValueError ('must define at least one ordering operation: <> <=> = ') 72 root = max (roots) # prefer _ lt _ to _ le _ to _ gt _ to _ ge _ 73 for opname, opfunc in convert [root]: 74 if opnamenot in roots: 75 opfunc. _ name __= opname76 opfunc. _ doc __= getattr (int, opname ). _ doc _ 77 setattr (cls, opname, opfunc) 78 return cls this article is all over, if I have time, I will sort out the source code of a modifier used to check the parameter type and put it up. It is an application :)

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.