The directory is as follows:

1. What is a decorator?


2. How to use decorators?


3. Built-in decorators

First, what is decoration?

A decorator, as its name suggests, is a function that enhances the functionality of a function or class.

That might be a little tricky to say.

For example: how to calculate the execution time of a function?

Here, you need to calculate the time of the add function.

# function
def add(a, b):        
    res = a + b        
    return resCopy the code

You might write it like this

import time


def add(a, b)    
    start_time = time.time()    
    res = a + b    
    exec_time = time.time() - start_time    
    print("The add function takes: {}".format(exec_time))    
    return resCopy the code

At this point, the boss asks you to calculate the time of the subtraction function (sub). Without decorators, you have to write a subtraction code again.

def sub(a, b)    
    start_time = time.time()    
    res = a - b    
    exec_time = time.time() - start_time    
    print("Sub function, the time is: {}".format(exec_time))    
    return resCopy the code

It’s cumbersome and inflexible, and if the code that counts the time changes, you have to change every function.

So, we need to introduce decorators.

The code after using the decorator looks like this

import time


Define the decorator
def time_calc(func):
    def wrapper(*args, **kargs):        
        start_time = time.time()        
        f = func(*args,**kargs)        
        exec_time = time.time() - start_time       
        return f    
    return wrapper   
    
# Use decorators
@time_calc    
def add(a, b):
    return a + b
    
@time_calc
def sub(a, b):    
    return a - bCopy the code

Doesn’t it look fresher?

What decorators do: Enhance functions. Specifically, they can decorate functions as well as classes.

How decorators work: Functions are first-class citizens of Python, and functions are objects.

Define decorator

def decorator(func):
    def wrapper(*args,**kargs): 
        You can customize the parameters passed in
        print(func.__name__)
        Return the call of the method name argument passed in
        return func(*args,**kargs) 
    Return the name of the inner function
    return wrapperCopy the code

Second, use decorators

Assume that the decorator is a defined decorator.

Method 1: Don’t use the @ symbol

No arguments are passed to the decoratorF = decorator(function name)When the decorator passes a parameterF = (decorator(argument))(function name)Copy the code

Method two: use the syntactic sugar @ symbol

# defined decorator
@decorator 
def f():  
    pass

Execute the decorated function
f()Copy the code

Decorators may or may not take parameters.

Decorators that pass no parameters themselves (using a two-tier function-defined decorator)

def login(func):        
    def wrapper(*args,**kargs):                
        print('Function name :%s'% func.__name__)                
        return func(*args,**kargs)        
    return wrapper    
    
@login
def f():       
    print('inside decorator! ')        

f()

# output:
# >> function name :f
# >> Function itself: Inside decorator!Copy the code

Decorators that pass in parameters themselves (using a three-tier function-defined decorator)

def login(text):
    def decorator(func):
        def wrapper(*args,**kargs):            
            print('%s----%s'%(text, func.__name__))
            return func(*args,**kargs)
        return wrapper
    return decorator

# is equivalent to ==> (login(text))(f) ==> return wrapper
@login('this is a parameter of decorator')  
def f():    
    print('2019-06-13')

# is equivalent to the = = > (login (text)) (f) () = = > call wrapper () and returns the f ()
f() 

# output:
# => this is a parameter of decorator----f
# = > 2019-06-13Copy the code

Three, built-in decorator

There are three common built-in decorators: @Property, @StaticMethod, and @classMethod

@property

To use an in-class method as a property, you must have a return value, equivalent to a getter;

If the @func.setter decorator is not defined, it is read-only

class Car:

    def __init__(self, name, price):
        self._name = name
        self._price = price    
     
    @property
    def car_name(self):
        return self._name
        
     # car_name Is a read-write attribute
     @car_name.setter
     def car_name(self, value):
         self._name = value
         
     # car_price is a read-only property
     @property
     def car_price(self):
         return str(self._price) + '万'
         
benz = Car('benz'30),print(benz.car_name)   # benz
benz.car_name = "baojun"
print(benz.car_name)   # baojun
print(benz.car_price)  # 300000Copy the code

@staticmethod

Static methods that don’t need to represent their own object’s self and CLS arguments of their own class, just like using a function.

@classmethod

Class method. No self argument is required, but the first argument needs to be a CLS argument representing its own class.

example

class Demo(object):

    text = "A comparison of the three methods"
    
    def instance_method(self):
        print("Call instance method")

    @classmethod
    def class_method(cls):
        print("Calling class methods")
        print("Access class attributes in class methods text: {}".format(cls.text))
        print("Call instance method instance_method: {} in class method".format(cls().instance_method()))

    @staticmethod
    def static_method():
        print("Calling static methods")
        print("Access class attributes in static methods text: {}".format(Demo.text))
        print("Call instance method instance_method: {} in static method".format(Demo().instance_method()))

if __name__ == "__main__":
    Instantiate the object
    d = Demo()
    
    Objects can access instance methods, class methods, and static methods
    Access the text property through the object
    print(d.text)
    
    Call instance methods from objects
    d.instance_method()
    
    Call a class method from an object
    d.class_method()
    
    Call static methods from objects
    d.static_method()
    
    Classes can access class methods, static methods
    Access the text property through the class
    print(Demo.text)
    
    Call class methods through classes
    Demo.class_method()
    
    Call a static method from a class
    Demo.static_method()Copy the code

@staticMethod and @classMethod

In the above example, we can see that,

The difference between

When defining a staticmethod or a class method, the @staticmethod decorates a staticmethod that requires the class name to access a class attribute or call an instance method.

The @classmethod method decorates the classmethod by passing a CLS parameter that represents the class, thus avoiding hard-coding the class name by hand.

Both static and class methods are actually written the same way, usually through the class name. Static method () or class name. Class method ().

Static and class methods can also be called with instantiated objects, but to distinguish them from instance methods, it is best to call static and class methods with classes.

Usage scenarios

So, when you define a class,

Use @staticMethod if you don’t need a class-related attribute or method.

If you need a class-specific property or method, and you want to indicate that the method is generic to the entire class rather than object specific, you can use the @classMethod method.

There are also some other github summaries: test development interview resources, review material summaries

If you’re interested, check it out.