Advanced Functions - decorator

A good application is the closure of the decorator expand !!!

Dian a no-argument decorator

1.1 What is a decorator

Device refers to the tool, and the function of the program is to have a functional tool, it refers to a decorator to add additional functionality to the decorator object. Therefore, the definition of decorator is the definition of a function, but the function of the function is used to add additional functionality to other functions.

have to be aware of is:

Decorator itself can actually be any object that can be called
an object to be decorated can be any callable objects

1.2 Why use decorator

If we have a project on line, we need to modify a particular method, but we do not want to modify the method of use, this time you can use decorator. Because the software maintenance should follow the open closed principle that once the software on-line operation, maintenance and modification of software source code is closed, the extended function refers to the open.

Achieve decorator must follow two principles:

Decorative objects does not modify the source code
does not modify the decorated object invocation
is actually add new features to the object to be decorated under the premise of following the above two principles decorators.

1.3 how to use decorator

Changes in the source code

import time

def index():
    start = time.time()
    print('welcome to index')
    time.sleep(1)
    end = time.time()
    print(F"index run time is {start-end}")

index()

welcome to index index run time is -1.0008180141448975
Write duplicate code

import time

def index():
    print('welcome to index')
    time.sleep(1)

def f2():
    print('welcome to index')
    time.sleep(1)

start = time.time()
index()
end = time.time()
print(F"index run time is {start-end}")

start = time.time()
f2()
end = time.time()
print(F"f2 run time is {start-end}")

welcome to index index run time is -1.0046868324279785 welcome to index f2 run time is -1.000690221786499
The first parameter passing mode: change the way calls

import time

def index():
    print('welcome to index')
    time.sleep(1)

def time_count(func):
    start = time.time()
    func()
    end = time.time()
    print(f"{func} time is {start-end}")

time_count(index)

welcome to index <function index at 0x102977378> time is -1.000748872756958
The second parameter passing mode: packet function - Outsourcing

import time

def index():
    print('welcome to index')
    time.sleep(1)

def time_count(func):
    # func = 最原始的index
    def wrapper():
        start = time.time()
        func()
        end = time.time()
        print(f"{func} time is {start-end}")
    return wrapper

# f = time_count(index)
# f()

index = time_count(index)  # index为被装饰函数的内存地址,即index = wrapper
index()  # wrapper()

welcome to index <function index at 0x102977730> time is -1.0038220882415771

1.4 perfect decorator

Above the decorator, the last call index () when, in fact, is calling wrapper (), and therefore the time if the original index () that returns a value, wrapper () returns the same value as the return value should be and index () of the return value, that is, we need to synchronize the original index () and wrapper () method.

import time


def index():
    print('welcome to index')
    time.sleep(1)

    return 123

def time_count(func):
    # func = 最原始的index
    def wrapper():
        start = time.time()
        res = func()
        end = time.time()
        print(f"{func} time is {start-end}")

        return res
    return wrapper

index = time_count(index)
res = index()
print(f"res: {res}")

welcome to index <function index at 0x102977620> time is -1.0050289630889893 res: 123
If the original index () method requires mass participation, then we decorator before this function can not be achieved, due to the wrapper () = index (), so give wrapper () method to pass parameters.

import time


def index():
    print('welcome to index')
    time.sleep(1)
    return 123

def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    return name

def time_count(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print(f"{func} time is {start-end}")

        return res
    return wrapper

home = time_count(home)

res = home('egon')
print(f"res: {res}")

welcome egon to home page <function home at 0x102977378> time is -1.0039079189300537 res: egon

1.5 decorator syntax sugar

In the decorative function just above, and is written on a separate line @ decorator name

import time

def time_count(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        end = time.time()
        print(f"{func} time is {start-end}")

        return res
    return wrapper

@time_count  # home = time_count(home)
def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

    return name

@time_count  # index = time_count(index)
def index():
    print('welcome to index')
    time.sleep(1)

    return 123

res = home('egon')
print(f"res: {res}")

welcome egon to home page <function home at 0x102977620> time is -1.0005171298980713 res: egon

1.6 decorator template

Double decorator template

def deco(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res return wrapper

Three decorative template (there are parameters decorator)

General parameters Up to three layers, more layers can also be set, but it does not make sense, to achieve sufficient decorative layer 3 itself want to add functionality needs, of course, you can also give a performance function or class want to achieve more decorative function decorators to achieve different case scenarios
in advance that under the Ha ...


Dian has two parameters decorator

No parameters set decorator only two layers, this section will tell a three-set decorator - there is a reference decorator, but now let's implement a registered user login decorators.

import time

current_user = {'username': None}

def login(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):
        if current_user['username']:
            res = func(*args, **kwargs)
            return res
        user = input('username: ').strip()
        pwd = input('password: ').strip()

        if user == 'nash' and pwd == '123':
            print('login successful')
            current_uesr['usre'] = user
            res = func(*args, **kwargs)
            return res
        else:
            print('user or password error')
    return wrapper

@login
def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)
    return name

@login
def index():
    print('welcome to index')
    time.sleep(1)
    return 123

res = index()

username: nash password: 123 login successful welcome to index
For the above login registration, information about our users to log in successfully write memory of them. But in the industry, user information may exist in the text, mysql in, mongodb them, but we only allow users to file information from the user can be authenticated. Therefore, we can rewrite the above decorator.

import time

current_user = {'username': None}


def login(func):
    # func = 最原始的index
    def wrapper(*args, **kwargs):

        if current_user['username']:
            res = func(*args, **kwargs)
            return res

        user = input('username: ').strip()
        pwd = input('password: ').strip()
        
        engine = 'file'

        if engine == 'file':
            print('base of file')
            if user == 'nash' and pwd == '123':
                print('login successful')
                current_uesr['usre'] = user
                res = func(*args, **kwargs)
                return res
            else:
                print('user or password error')
        elif engine == 'mysql':
            print('base of mysql')
        elif engine == 'mongodb':
            print('base of mongodb')
        else:
            print('default')
    return wrapper

@login
def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

@login
def index():
    print('welcome to index')
    time.sleep(1)


res = index()

username: nash password: 123 base of file login successful welcome to index

2.1 three-closure

def f1(y):
    def f2():
        x = 1
        def f3():
            print(f"x: {x}")
            print(f"y: {y}")
        return f3
    return f2

f2 = f1(2)
f3 = f2()
f3()

x: 1 y: 2
Now we need to change, and we need to determine how users get a dynamic password user, if it is the type of file, we then let the user authentication. Therefore, we can use the parameters have decorator.

import time

current_uesr = {'username': None}


def auth(engine='file'):

    def login(func):
        # func = 最原始的index
        def wrapper(*args, **kwargs):
            if current_user['username']:
                res = func(*args, **kwargs)

                return res

            user = input('username: ').strip()
            pwd = input('password: ').strip()

            if engine == 'file':
                print('base of file')
                if user == 'nash' and pwd == '123':
                    print('login successful')
                    current_uesr['usre'] = user
                    res = func(*args, **kwargs)
                    return res
                else:
                    print('user or password error')
            elif engine == 'mysql':
                print('base of mysql, please base of file')
            elif engine == 'mongodb':
                print('base of mongodb, please base of file')
            else:
                print('please base of file')

        return wrapper

    return login

@auth(engine='mysql')
def home(name):
    print(f"welcome {name} to home page")
    time.sleep(1)

@auth(engine='file')
def index():
    print('welcome to index')
    time.sleep(1)

res = index()

username: nash password: 123 base of file login successful welcome to index
As the two decorators, parameters must have a fixed place func, but three decorators lifted this restriction. We can not just use a single parameter of the above three decorators, just need to add a few parameters in three decorator multiple parameters. That decorator to three, extra layer actually useless.


Wed and decoration is applied to the class

Review what is decorator:
  the decorator definition: essentially function (higher-order functions), the function is to add new functionality to other functions (objects)

A class decorator basically works as follows:

def deco(cls):
    print('类的装饰器=========》')
    print('='*20)
    return cls

@deco      #====> Foo = deco(Foo)
class Foo:
    pass

Second, the above simple decoration is no argument, and now we add parameters

def cls_decorator(**kwargs):            #支持传入参数(属性和对应的值),字典形式
    def deco(cls):
        for key,val in kwargs.items():
            setattr(cls,key,val)        #给类设置对应的属性和值
        return cls
    return deco

@cls_decorator(name='Menawey',age=24,gender='male')        # 1 运行cls_decorator(...),返回deco;2 @deco===> Peolple = deco(People)
#相当于给People类设置了name、age、gender属性
class People:
    pass

print(People.__dict__)                                   #查看被装饰过的类的属性字典

By thus dynamically to different classes increase at his attributes instantiated

Third, in conjunction with the descriptor
  by using the decorative assembly and the class descriptor you can perform many functions, such as adding the class attribute and the type attribute can be defined.

#描述符
class Desc:
    def __init__(self,key,value_type):
        self.key = key
        self.value_type = value_type
    def __get__(self, instance, owner):
        return instance.__dict__[self.key]
    def __set__(self, instance, value):
        if not isinstance(value,self.value_type):
            raise TypeError('%s 传入的类型不是 %s'%(self.key,self.value_type))
        instance.__dict__[self.key] = value
    def __delete__(self, instance):
        instance.__dict__.pop(self.key)

#装饰器
def cls_decorator(**kwargs):            #支持传入参数(属性和对应的值),字典形式
    def deco(cls):
        for key,val in kwargs.items():    #这里需要用到描述符对属性进行代理,但是val是指定的类型,所以要用Desc(key,val)来描述为对应的值
            setattr(cls,key,Desc(key,val))        #给类设置对应的属性和值
        return cls
    return deco

@cls_decorator(name=str,age=int,gender=str,salary=float)    #使用装饰器

#被装饰和描述的类
class People:
    def __init__(self,name,age,gender,salary):
        self.name = name
        self.age = age
        self.gender = gender
        self.salary = salary

p1 = People('Menawey',24,'male',11.1)  #因为gender属性指定的是sstr,但是TypeError: age 传入的类型不是 <class 'int'>
print(People.__dict__)


Four Dian brain big wide open

What ?? !! python class as a decorator !!! ??
Reference link:
https://blog.csdn.net/qq_29767317/article/details/80799410

da



#重写了__call__方法,类的对象就能够被调用,直接使用t()来调用类,并打印__call__方法里面的内容
class Test(object):
    print("--------test1----------")
    def __call__(self, *args, **kwargs):
        print(da) #注意一点,__call__方法里面的是最后执行。
    def  eat(self):
        print("-----------eat-------------")
    print("---------test2---------")
t = Test()
t() 

The results:
D: \ python3.6 \ pythonw.exe F: / Python project / 09Day / 03python Advanced / 01 class as a decorator .py
-------- ---------- test1
test2 --------- ---------
--------- --------- the Test

Class as a decorator:

class Test(object):
    def __init__(self,func):
        print("-------初始化-------")
        print("func name is %s" %func.__name__)
        self.__func = func #类的私有属性self.__func也指向了test1函数的内存地址。
    def __call__(self, *args, **kwargs): #test1 = Test(test1) #调用类的对象。就会调用call方法。
        print("------装饰器中的功能-------")
        self.__func() #self.__func指向了函数test1的内存地址。这句话相当于执行test1()函数。


#使用类作为装饰器,需要重写Call方法,没有调用test1()方法的时候,执行代码得到下面的结果
# -------初始化-------
# func name is test1

@Test #相当于 test1 = Test(test1)  也相当于func指向了下面函数test1的名字, 前面的test1指向了 Test()这个对象。
# 调用test1对象的时候相当于调用类方法Test(),调用类方法必调用__call方法,调用call方法的时候,先执行    print("------装饰器中的功能-------")
#然后在执行self.__func() ,因为self.__func函数指向的是test1函数,test1()相当于执行self.__func().
def test1():
    print("----test1---------")

test1() #调用test1

D: \ python3.6 \ pythonw.exe F: / python project / 09Day / 03python Advanced / 02 class as a decorator .py
------- initialization -------
FUNC name IS test1
--- --- decorator function -------
---- --------- test1

Guess you like

Origin www.cnblogs.com/suren-apan/p/11374767.html