Decorators, Iterators, Generators in Python

1. Decorator

  • The utensil that decorates other people can be any callable object itself, and the decorated object can also be any callable object.
  • Emphasize the principles of decorators: 1 Do not modify the source code of the decorated object 2 Do not modify the calling method of the decorated object
  • The goal of the decorator: add new functionality to the decorated object under the premise of following 1 and 2
  • Open closed principle: closed for modification, open for extension
import time

def timmer(fun):
    start_time=time.time()
    fun()
    end_time=time.time()


def fun1():
    print("in func1")

timmer(fun1) #Change the execution of the original function
  • It is necessary to wrap this function with a closure

import time

def timmer(fun):
    def inner():
        start_time=time.time()
        fun()
        end_time=time.time()
        print("run in {} time {}".format(fun,end_time-start_time))
    return inner # actually passes the function name to timmer, timmer executes, the reason why inner is returned is because inner cannot be called globally


def fun1():
    print("in func1")

print(timmer(fun1)) #Can run, in fact, it is to execute Inner, the purpose is to call it globally,
fun1=timmer(fun1) #The function itself is a variable, and the variable values ​​are exchanged
fun1()                  
  • In this way, the most basic decorator is completed. Python provides us with syntactic sugar. A complete decorator is as follows: it will allow the function to pass parameters and return the same value.

import time

def timmer(fun):
    def inner(*args,**kwargs):
        start_time=time.time()
        ret = fun(*args,**kwargs)
        end_time=time.time()
        print("run in {} time {}".format(fun,end_time-start_time))
        return right
    return inner # actually passes the function name to timmer, timmer executes, the reason why inner is returned is because inner cannot be called globally

@timmer
def fun1(num):
    print("in func1 {}".format(num))
    return 123

# print(timmer(fun1)) #Can run, in fact, it is to execute Inner, the purpose is to call it globally,
# fun1=timmer(fun1) #The function itself is a variable, and the variable values ​​are exchanged
print(fun1(1))
  • This can decorate multiple functions, but what about batch changes? If you don't want to decorate, do you need to remove them one by one?

import time

def outer():
    Flag=False
    def timmer(fun):
        def inner(*args,**kwargs):
            if Flag:
                start_time=time.time()
                ret = fun(*args,**kwargs)
                end_time=time.time()
                print("run in {} time {}".format(fun,end_time-start_time))
                return right
            else:
                ret = fun(*args, **kwargs)
                return right
        return inner # actually passes the function name to timmer, timmer executes, the reason why inner is returned is because inner cannot be called globally
    return timmer   

@outer() #The reason for the execution is to put the memory address of the return value of outer timmer function here, which is actually @timmer
def fun1(num):
    print("in func1 {}".format(num))
    return 1

@outer()
def fun2(num):
    print("in func2 {}".format(num))
    return 2

@outer()
def fun3(num):
    print("in func3 {}".format(num))
    return 3

print(fun1(1))
print(fun2(2))
print(fun3(3))
  • Write a decorator to add authentication functions to multiple functions (the user's account password comes from a file), requiring a successful login, and subsequent functions do not need to enter the user name and password

  • Use small knowledge points eval

login_status={"user":None,"status":False}

def outer():
    Flag=True
    def auth(func):
        def inner(*args,**kwargs):
            if Flag:
                with open("user.txt",encoding="utf-8") as read_f:
                    if login_status['user'] and login_status['status']:
                        ret = func (* args, ** kwargs)
                        return right
                    user_info=eval(read_f.read())
                    name=input("your name>>:").strip()
                    password=input("your password>>:").strip()
                    if name in user_info and user_info[name]["password"] == password:
                        login_status["user"]=name
                        login_status["status"]=True
                        print(login_status)
                        ret = func (* args, ** kwargs)
                        return right
                    else:
                        print("bad")
            else:
                ret = func (* args, ** kwargs)
                return right
        return inner
    return auth


@outer()
def fun1():
    print("in func1")
    return 1

@outer()
def fun2():
    print("in func2")
    return 2

@outer()
def fun3():
    print("in func3")
    return 3

fun1()
fun2()
fun3()
  • Multiple decorators decorate the same function

def wrapper1(func):
    def inner():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner

def wrapper2(func):
    def inner():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner

@wrapper2
@wrapper1
def f():
    print('in f')

f()

  The reasons for the results are as follows:

 Decorator practice:

#Write a function to download webpage content, the required function is: the user passes in a url, and the function returns the result of the download page
import time
from urllib.request import urlopen

def wrapper(func):
    def inner(*args,**kwargs):
        start_time=time.time()
        ret = func(*args,**kwargs).decode('utf-8')
        end_time=time.time()
        print("{} time is {}".format(*args,end_time-start_time))
        return right
    return inner

@wrapper
def get(url):
    return urlopen(url).read()

# print(get('http://www.baidu.com'))
get('http://www.baidu.com')

2. Iterator

  •  In fact, iteration is what we call it. The data in a data set can be "taken out one by one", which is called iteration .

  • The definition of the iterable protocol is very simple, that is, there is an __iter__ method inside.
from collections import Iterable

l = [1, 2, 3, 4]
t = (1, 2, 3, 4)
d = {1: 2, 3: 4}
s = {1, 2, 3, 4}

print(isinstance(l, Iterable))
print(isinstance(t, Iterable))
print(isinstance(d, Iterable))
print(isinstance(s, Iterable))
print (dir ([1,2]))
  • You can also traverse with __next__ without relying on for loops

l=[1,2,3,4]
l_iter=l.__iter__() #First turn the iterable object into an iterator
print(l_iter.__next__()) # Take values ​​in turn
print(l_iter.__next__()) # Take values ​​in turn
print(l_iter.__next__()) # Take values ​​in turn
print(l_iter.__next__()) # Take values ​​in turn
  • while..try..

l=[1,2,3,4]
l_iter=l.__iter__() #First turn the iterable object into an iterator
# print(l_iter.__next__()) # Take values ​​in turn
# print(l_iter.__next__()) # Take values ​​in turn
# print(l_iter.__next__()) # Take values ​​in turn
# print(l_iter.__next__()) # Take values ​​in turn


while True:
    try:
        item = l_iter.__next__()
        print(item)
    except StopIteration:
        break

3. Generator

  • A function that contains the yield keyword is a generator function. yield can return values ​​from functions for us

  • But yield is different from return. The execution of return means the end of the program. Calling the generator function will not get the specific value returned, but an iterable object.

  • Every time you get the value of this iterable object, you can push the execution of the function and get a new return value. until the end of the function execution.

  • What are the benefits of generators? Just don't generate too much data in memory at once

def genrator_fun1():
    a=1
    yield a
    b=2
    yield b

g=genrator_fun1()
print(next(g))
print(next(g))
# Example of generator listening for file input

  

  

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

  

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324664573&siteId=291194637