Python tutorial 11 -- Python decorator

Source: Internet
Author: User
Tags python decorator

Python tutorial 11 -- Python decorator

A function is also an object, and a function object can be assigned to a variable. Therefore, a function can also be called through a variable.

The function object has a (Double underline + name + double underline) attribute. You can get the function name:

Now, let's assume that we want to enhance the functions of the now () function, for example, to automatically print logs before and after the function call, but do not want to modify the definition of the now () function, this method dynamically adds features during code execution, it is called "decorative thick ky" http://www.bkjia.com/kf/ware/vc/ "target =" _ blank "class =" keylink "> trim + sb7WysnPo6xkZWNvcmF0b3K + encrypt/K/aGjy/weight + tcRkZWNvcmF0b3KjrL/trim =" brush: java; ">def log(func): def wrapper(*args, **kw): print('call %s():' % func.__name__) return func(*args, **kw) return wrapper

Observe the preceding log. Because it is a decorator, a function is received as a parameter and a function is returned.
We need to use the @ Syntax of Python to place the decorator in the definition of the function:

def log(func):    def wrapper(*args, **kw):        print('call %s():' % func.__name__)        return func(*args, **kw)    return wrapper@logdef now():    print('2016-02-13')now()


Calling the now () function not only runs the now () function itself, but also prints a line of log before running the now () function.

Put @ log in the definition of the now () function, which is equivalent to executing the statement:

now = log(now)

Because log () is a decorator and returns a function, the original now () function still exists, but now the now variable with the same name points to the new function, so calling now () will execute the new function, that is, the wrapper () function returned in the log () function.

The Parameter definition of the wrapper () function is (* args, ** kw). Therefore, the wrapper () function can call any parameter. In the wrapper () function, first print the log and then call the original function.

If the decorator itself needs to input parameters, you need to write a high-level function that returns the decorator, which is a bit complicated to write. For example, to customize the log text:

def log(text):    def decorator(func):        def wrapper(*args, **kw):            print('%s %s():' % (text, func.__name__))            return func(*args,**kw)        return wrapper    return decorator

This is a layer-3 nested decorator. Its usage is as follows:

@log('execute')def now():    print('2016-02-13')now()

The execution result is as follows:

Compared with the two-layer nested decorator, the effect of layer-3 Nesting is as follows:

now = log('execute')(now)

Let's analyze the preceding statement. First, execute log ('execute ') and return the decorator function. when calling the returned function, the parameter is the now function, and the returned value is the wrapper function.

The definition of the preceding two types of decorator is correct. Because we have mentioned that a function is also an object and it hasNameBut we can see the function after decorator decoration, theirNameIt has changed from the original 'now 'to 'wrapper ':

now._name_'wrapper'

Because the returned wrapper () function name is 'wrapper ',NameAnd other attributes are copied to the wrapper () function. Otherwise, code execution that depends on the function signature will fail.

You do not need to write such code. The built-in Python functools. wraps is used to do this. Therefore, a complete decorator statement is as follows:

import functoolsdef log(func):    @functools.wraps(func)    def wrapper(*args, **kw):        print('call %s():' % func._name_)        return func(*args, **kw)    return wrapper

Or for the decorator with parameters:

import functoolsdef log(text):    def decorator(func):        @functools.wraps(func)        def wrapper(*args, **kw):            print('%s $s():' % (text, func._name_))            return func(*args, **kw)        return wrapper    return decorator()

Import functools is to import the functools module. The concept of the module will be discussed later. Now, remember to add @ functools. wraps (func) before defining wrapper.

Summary:

In the object-oriented (OOP) design pattern, decorator is called the decoration pattern. The decoration mode of OOP needs to be implemented through inheritance and combination. In addition to the decorator supporting OOP, Python directly supports decorator at the syntax level. Python decorator can be implemented using functions or classes.

Decorator can enhance functions of functions. Although it is a bit complicated to define, It is very flexible and convenient to use.

Compile a decorator to print logs of 'begincall' and 'end call' before and after function calling.

import functoolsdef log(func):    @functools.wraps(func)    def wrape(*args, **kw):        print('begin call')        execute = func(*args, **kw)        print('end call')        return execute    return wrape@logdef now():    print('2016-02-13')now()

Think about whether to write a @ log decorator so that it supports both:

@logdef f()    pass

It also supports:

@log('execure')def f():    pass

Method 1:

def log(text):    def decorator(func):        def wrapper(*args, **kw):            print('begin call')            print('%s : %s' % (text, func.__name__))            execute = func(*args, **kw)            print('end call')            return execute        return wrapper    if isinstance(text, str):        return decorator    func = text    text = 'execute'    return decorator(func)@log('execute')def now():    print('2016-02-13')now()

Method 2:

def log(text):    def decorator(func):        def wrapper(*args, **kw):            print('begin call')            print('%s : %s' % (text, func.__name__))            execute = func(*args, *kw)            print('end call')            return execute        return wrapper    if isinstance(text, str):        return decorator    func = text    text = 'execute'    return decorator(func)@logdef now():    print('2016-02-13')now()

The third type is written by the great gods. The two are combined.

import functoolsdef log(arg):    def decorator(func = arg):        text = 'call' if func == arg else arg        @functools.wraps(func)        def wrapper(*args, **kw):            print('%s %s():' % (text, func.__name__))            return (func(*args, **kw), print('end %s %s():' % (text, func.__name__)))[0]        return wrapper    return decorator() if callable(arg) else decorator@logdef now():    print('2016-02-13: 1')now()@log('execute')def now1():    print('2016-02-13: 2')now1()

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.