Python adorner and aspect-oriented programming

Source: Internet
Author: User
Tags function definition python decorator

Let's talk about decorators today. The adorner is a well-known design pattern, which is often used in scenes where there is a demand for facets, with the classic insert log, performance test, transaction processing, and so on. Decorators are a great design for solving such problems, and with adorners, we can pull out a lot of the same code that is not relevant to the function itself and continue to reuse it. In summary, the function of an adorner is to add additional functionality to an already existing object.

1. Getting Started with adorners

1.1. How is the demand coming?

The definition of adorners is very abstract, let's look at a small example.

def foo ():

print ' in foo () '

Foo ()

This is a very boring function, yes. But suddenly there is a more boring person, we call him B-June, said I want to see how long it takes to execute this function, OK, then we can do this:

Import time

def foo ():

Start = Time.clock ()

print ' in foo () '

End = Time.clock ()

print ' used: ', End-start

Foo ()

Very well, the features look impeccable. But the egg-ache B-June suddenly don't want to see this function, he to another called Foo2 's function produced a more intense interest.

What do we do? If the above new additions to the code to copy into the Foo2, which made a big taboo ~ Copy what is not the most annoying it! And what if B-June continues to look at the other functions?

1.2. Status quo, is change also

Remember, the function is a one-time citizen in Python, so we can consider redefining a function Timeit, passing the Foo reference to him, then calling Foo in Timeit and timing it so that we do not have to change the Foo definition, and, No matter how many functions B has seen, we don't have to modify the function definition!

Import time

def foo ():

print ' in foo () '

def Timeit (func):

Start = Time.clock ()

Func ()

End =time.clock ()

print ' used: ', End-start

Timeit (foo)

There seems to be no logical problem, everything is fine and functioning properly! ...... Wait, we seem to have modified the code for the calling section. Originally we called this: Foo (), modified to become: Timeit (foo). In this case, if Foo is called at N, you will have to modify the code in the N place. Or, to be more extreme, consider that the code in which it is called cannot modify the situation, for example: This function is something you give to someone else.

1.3. Minimize Changes!

That being the case, we'll try to figure out how to do this without modifying the calling code, which 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 ... Think of ways to unify the parameters! If Timeit (foo) does not directly produce a call effect, but instead returns a function that is consistent with the Foo argument list ... It's good to have the return value of Timeit (foo) assigned to Foo, and then the code that calls Foo () doesn't have to be modified at all!

#-*-Coding:utf-8-*-

Import time

def foo ():

print ' in foo () '

# define a timer, pass in one, and return another method with the timer feature attached

def Timeit (func):

# define an inline wrapper function that adds a timing function to the incoming function

def wrapper ():

Start = Time.clock ()

Func ()

End =time.clock ()

print ' used: ', End-start

# Returns the Wrapped function

Return wrapper

foo = Timeit (foo)

Foo ()

In this way, a simple timer is ready! We only need to call Foo after the definition of foo, and foo = Timeit (foo), to achieve the purpose of timing, which is the concept of adorners, which looks like Foo was Timeit decorated. In this example, the function enters and exits with timing, which is called a cross plane (Aspect), which is called aspect-oriented programming (Aspect-oriented programming). In comparison to the top-down execution of traditional programming habits, a logic is inserted horizontally in the process of function execution. In a specific business area, you can reduce the amount of repetitive code. Aspect-oriented programming there are quite a lot of terminology, here is not much to do introduction, interested in the words can find relevant information.

This example is for demonstration purposes only, and does not consider Foo with parameters and a return value of the case, the task of perfecting it to you:)

2. Additional support for Python

2.1. Grammatical sugars

The above code seems to be no longer streamlined, and Python provides a syntactic sugar to reduce the amount of character input.

Import time

def Timeit (func):

def wrapper ():

Start = Time.clock ()

Func ()

End =time.clock ()

print ' used: ', End-start

Return wrapper

@timeit

def foo ():

print ' in foo () '

Foo ()

Focusing on the @timeit of line 11th, adding this line to the definition is exactly equivalent to writing foo = Timeit (foo), and never assume that @ has additional magic. In addition to the less character input, there is an additional benefit: it looks more like a decorator.

Here are a list of two simple examples

Adorner with no parameters

@A

def foo ():

Pass

Equivalent:

def foo ():

Pass

foo = A (foo)

Adorner with parameters

@A (ARG)

def foo ():

Pass

is equivalent to:

def foo ():

Pass

Foo = A (arg) (foo)

You can see that the first adorner is a function that returns a function, and the second decorator is a function that returns a function.

2.2. Built-in adorner

There are three built-in decorators, Staticmethod, Classmethod, and property, respectively, to make the instance methods defined in the class into static, class, and class properties. Because functions can be defined in a module, static and class methods are not much useful unless you want to fully object-oriented programming. Attributes are not essential, and Java does not have the properties to live very well. From my personal Python experience, I have not used the property, and the frequency of using Staticmethod and Classmethod is very low.

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 property, and if it is writable, a setter needs to be defined:

@name. Setter

def name (self, name):

Self._name = Name

2.3. Functools Module

The Functools module provides two adorners. This module was added after Python 2.5, and generally everyone should use more than this version. But my usual working environment is 2.4 t-t

2.3.1. Wraps (wrapped[, assigned][, updated]):

This is a very useful decorator. A friend who has seen the previous reflection should know that the function has several special properties such as the function name, after being decorated, the function name Foo in the above example becomes the name of the wrapper function wrapper, and if you want to use reflection, it can result in unexpected results. This decorator solves this problem by preserving the special properties of the decorated function.

Import time

Import Functools

def Timeit (func):

@functools. Wraps (func)

def wrapper ():

Start = Time.clock ()

Func (*args, **kwargs)

End =time.clock ()

print ' used: ', End-start

Return wrapper

@timeit

def foo (x):

print ' in foo () '

Foo (1)

Print foo.__name__

Notice the 5th line first, and if you comment on this line, foo.__name__ will be ' wrapper '. In addition, I believe you have noticed that this decorator has a parameter. In fact, he has two other optional arguments, the property names in assigned are replaced with assignments, and the property names in updated are merged using update, and you can get their default values by looking at the source code of Functools. For this adorner, it is equivalent to wrapper = Functools.wraps (func) (wrapper).

Finally, an adorner that validates the user's operating rights in a job

From django.utils.decorators import Available_attrs

From Functools Import Wraps

def auth_power (Mod_value, action):

"""

Verify Operation Permissions

@auth_power (mod_value= ' order_manage ', action= ' delete ')

def my_view (Request):

# ...

"""

Permit_code = ' esms_%s_%s '% (mod_value,action)

def decorator (func):

def inner (request, *args, **kwargs):

user = Request.user

If SysRolePermit.objects.filter (Role_code=user.role_code, Permit_code=permit_code). Exists ():

return func (Request, *args, **kwargs)

Else

Return Httpresponseredirect ('/nopower/')

Return Wraps (func, Assigned=available_attrs (func)) (inner)

return decorator

Article content Source:

Http://www.cnblogs.com/huxi/archive/2011/03/01/1967600.html

Http://www.cnblogs.com/itech/archive/2011/12/31/2308766.html

Python Decorator Step-up tutorial

Http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.html

Auto-traverse class method add adorner

http://blog.csdn.net/zylcf818/article/details/5342276

Python adorner and aspect-oriented programming

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.