day 17 no reference decorator

Today's content:

Decorator

"""
1.什么是装饰器
  具备某一功能的工具
  装饰:指的是为被装饰的对象添加新功能
  装饰器:就是用来为被装饰器对象添加新功能的工具
  ps:装饰器本身可以是任意可调用对象,被装饰器的对象也可以是任意可调用对象(我们所学的能够被调用的对象就是函数了,那么一会儿我们要写两个函数,一个是装饰器,一个是普通函数)

2.为何要用装饰器
	装饰器可以在不改变被装饰对象源代码以及调用方式的情况下给被装饰对象添加新的功能
	装饰器遵循的两大原则:
		1.不修改被装饰对象的源代码
		2.不修改被装饰对象的调用方式
	
3.怎么用装饰器
"""
"""
预备知识点
import time 
print(time.time())  # 获取时间戳格式时间
time.sleep(3)  # 睡3秒
"""

# 统计函数运行时间
import time
def index():
  print('index...')
  time.sleep(3)

start_time = time.time()
index()
end_time = time.time()
print('index函数执行时间:%s'%start_time-end_time)
# ps:这种方式实现了统计函数执行时间,并且遵循装饰器的两个原则,但是弊端也很明显,如果有一百个函数都需要统计运行时间,就会出现严重的代码重复情况


# 装饰器简单实现版本推导
# 将重复的代码封装成一个函数来减少代码重复

# 步骤1(功能写死了,只能统计index函数的运行时间)
def wrapper():
  start_time = time.time()
  index()
  end_time = time.time()
  print('index函数执行时间:%s'%start_time-end_time)
  
# 步骤2(函数名当作参数传入,改变了调用方式)
def wrapper(func):
  start_time = time.time()
  func()
  end_time = time.time()
  print('index函数执行时间:%s'%start_time-end_time)
wrapper(index)

# 步骤3(函数需要参数,上面直接传参的方式不可行,只能用另一种闭包的方式)
def outter(func):  # func = 最原始的传入的函数(index)的内存地址
  # func = index  这样写死了
  def wrapper():
    start_time = time.time()
    func()  # 最原始的传入的函数(index)的内存地址
    end_time = time.time()
    print('index函数执行时间:%s'%start_time-end_time
  return wrapper
f = outter(index)
f()
"""
ps:上面这种方式貌似也无法满足装饰器的两大原则,其实是完全有可能的
"""
index = outter(index)  # 先执行等号右边的函数将wrapper函数内存地址返回,然后再用一个与函数名index重名的变量名index指代wrapper,虽然把函数名冲掉了但是问题不大
index()  # wrapper()  满足了装饰器的两大基本原则

Decorator upgrade version

"""函数参数及返回值的添加"""
def index():
  print('index')
   
def home(name):
  print('hello %s'%name)
  
def outter(func):  # func = 最原始的传入的函数的内存地址
  def wrapper():
    start_time = time.time()
    func()  # 最原始的传入的函数的内存地址
    end_time = time.time()
    print('index函数执行时间:%s'%start_time-end_time
  return wrapper
# 之前装饰器的index现在我们想装饰home
home = outter(home)  # home =wrapper
home()  # wrapper() 内部的func()>>>home() 没有传参报错
"""home需要参数其实需要通过wrapper传递进去,也就意味着需要写wrapper(name),func(name)"""         
def outter(func):  # func = 最原始的传入的函数的内存地址
  def wrapper(name):
    start_time = time.time()
    func(name)  # 最原始的传入的函数的内存地址
    end_time = time.time()
    print('函数执行时间:%s'%start_time-end_time
  return wrapper
# 这样确实解决了装饰home函数带来的问题,但是再回去装饰index又报错了,因为index函数不需要参数 现在的问题就变成如何给需要参数的传参,不需要参数的函数就不传参并且是任意类型
def outter(func):  
  def wrapper(*args,**kwargs):  # 外部函数接受的参数原封不动的传递给内部的函数
    start_time = time.time()
    func(*args,**kwargs)  
    end_time = time.time()
    print('函数执行时间:%s'%start_time-end_time
  return wrapper
# 分析装饰index和home参数的变化
          
"""再来想如果我们的普通函数有返回值的话该怎么解决"""

Decorator syntax sugar

def outter(func):  
  def wrapper(*args,**kwargs):  
    start_time = time.time()
    res = func(*args,**kwargs)  
    end_time = time.time()
    print('函数执行时间:%s'%start_time-end_time
    return res
  return wrapper
@outter  # 自动执行index = wrapper(index)
def index():
    print('index')
@home
def home():  # 自动执行home = wrapper(home)
    print('home')

Authentication decorator

import time

def auth(func):
    def wrapper(*args,**kwargs):
        inp_user = input('please input your username: ').strip()
        inp_pwd = input('please input your password: ').strip()
        if inp_user == 'egon' and inp_pwd == '123':
            print('login successfull')
            res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数
            return res
        else:
            print('username or password error')
    return wrapper
@auth # index=auth(index) #index=wrapper
def index():
    print('welcome to index page')
    time.sleep(3)
index() #wrapper()

Superposition of multiple decorators

# 将上面的两个装饰器都拿过来分析
import time

def timmer(func):  #func=wrapper2
    def wrapper1(*args,**kwargs):
        start=time.time()
        res=func(*args,**kwargs)  #res=wrapper2(*args,**kwargs)
        stop=time.time()
        print('run time is %s' %(stop - start))
        return res
    return wrapper1

def auth(func): #func=最原始的那个index的内存地址
    def wrapper2(*args,**kwargs):
        inp_user = input('please input your username: ').strip()
        inp_pwd = input('please input your password: ').strip()
        if inp_user == 'egon' and inp_pwd == '123':
            print('login successfull')
            res=func(*args,**kwargs) # 调用最原始的那个/也就是被装饰的那个函数
            return res
        else:
            print('username or password error')
    return wrapper2

# 解释@语法的时候是自下而上运行
# 而执行装饰器内的那个wrapper函数时的是自上而下
@timmer # index=timmer(wrapper2) #index=wrapper1
@auth # index=auth(最原始的那个index的内存地址) #index=wrapper2
def index():
    print('welcome to index page')
    time.sleep(3)
index() #wrapper1()


# 三个装饰器
def outter1(func1): 
    print('加载了outter1')
    def wrapper1(*args,**kwargs):
        print('执行了wrapper1')
        res1=func1(*args,**kwargs)
        return res1
    return wrapper1

def outter2(func2): 
    print('加载了outter2')
    def wrapper2(*args,**kwargs):
        print('执行了wrapper2')
        res2=func2(*args,**kwargs)
        return res2
    return wrapper2

def outter3(func3):
    print('加载了outter3')
    def wrapper3(*args,**kwargs):
        print('执行了wrapper3')
        res3=func3(*args,**kwargs)
        return res3
    return wrapper3

@outter1 
@outter2 
@outter3 
def index():
    print('from index')

print('======================================================')
index()

Guess you like

Origin www.cnblogs.com/AaronY/p/12556469.html