首页 > 代码库 > 【python】-- 装饰器、迭代器、生成器

【python】-- 装饰器、迭代器、生成器

装饰器

装饰器本质是函数,是用来装饰其他函数,顾名思义就是,为其他的函数添加附件功能的。

一、装饰器原则:

  1. 不能修改被装饰函数的源代码

  2. 不能修改被装饰函数的调用方式

技术分享
def logging():
    print("logging...")
 
#正确写法,没有修改源码
def test1():
    pass
 
#错误写法,不能修改源码
def test1():
    pass
    logging()
 
# 调用方式,也不能被修改
test1()
View Code

 

二、装饰器知识:

  1. 函数即"变量"
  2. 高阶函数+嵌套函数 =》装饰器

1、函数即”变量“

python的内存机制,看如下代码:

#变量
x = 1
#函数
def test():
    pass

在内存图中是这样表示的:

技术分享

x、test 是变量名,保存在栈内存中,1、函数体  保存在堆内存中 

 

 2、高阶函数+嵌套函数 =》装饰器

装饰器实现过程:

第一步:原始代码

技术分享
def home():
    print("---首页----")
 
def TV():
    print("----TV----")

def music()
    print("---music-----")
View Code

第二步:想给部分模块加个登陆认证

技术分享
user_status = False #用户登录了就把这个改成True
 
def login():
    _username = "ABC" #假装这是DB里存的用户信息
    _password = "12345" #假装这是DB里存的用户信息
    global user_status
 
    if user_status == False:
        username = input("user:")
        password = input("pasword:")
 
        if username == _username and password == _password:
            print("welcome login....")
            user_status = True
        else:
            print("wrong username or password!")
    else:
        print("用户已登录,验证通过...")
 
def home():
    print("---首页----")
 
def TV():
    login() #执行前加上验证
    print("----TV----")
 
def music():
    print("----music----")
View Code

虽然这样实现了认证功能,但是修改了被装饰函数的源代码,违背了装饰器的原则”不能修改被装饰函数的源代码“

第三步:代码改进,使用高阶函数理念,把函数名当参数传递给认证函数login,这样可以不修改被装饰函数源代码的情况下完成登陆认证

技术分享
user_status = False #用户登录了就把这个改成True
 
def login(func):
    _username = "ABC" #假装这是DB里存的用户信息
    _password = "12345" #假装这是DB里存的用户信息
    global user_status
 
    if user_status == False:
        username = input("user:")
        password = input("pasword:")
 
        if username == _username and password == _password:
            print("welcome login....")
            user_status = True
        else:
            print("wrong username or password!")
    if user_status == True:
        print("用户已登录,验证通过...")
        func() #只要验证通过了,就调用相应功能 
 
def home():
    print("---首页----")
 
def TV():
    print("----TV----")
 
def music():
    print("----music----")  


login(TV) #需要验证就调用 login,把需要验证的功能 当做一个参数传给login  
View Code

 

 

 

虽然这样可以不修改被装饰函数源代码的情况下完成登陆认证,但是违背了装饰器原则”修改了被装饰函数的调用方式“,本来被装饰函数只需要TV()就可调用,现在变成了login(TV)

第四步:代码改进,使用匿名函数理念,将login(TV)变成 TV = login(TV) ,将函数当成值,赋值给变量名TV,跟关键字def 重新定义了TV是一样的效果,不过这样还有一个问题, TV = login(TV)这个赋值过程中,就把

函数TV给调用了,用户自己还没有调用,就自己自动调用肯定是不对的,这个时候需要用到嵌套函数的理念了,在认证函数login里面的再定义一个新函数login_inner,在login函数return(返回)login_inner函数名(对是return login_inner, 不是return  login_inner(), 因为return 函数名 返回的是函数在栈内容的内存地址,return 函数名+() 返回的是该函数的执行结果) 这样在TV = login(TV)赋值的时候,TV赋值的就不是 login(TV)的执行结果了,赋值的值是login_inner的内存地址,等用户再调用的时候 就是TV(),这样就没有改变被装饰函数的调用方式了。

 

 

装饰器装饰没有参数函数:

import time
 
#定义装饰器函数
def timmer(func):  # 把test1这个函数名作为参数传递进来 func=test1
    #定义装饰器中的内置函数
    def deco():
        start_time = time.time()
        func()   #相当于运行test1()
        stop_time = time.time()
        print("the func run time is %s"%(stop_time-start_time))
 
    return deco
 
#装饰test1函数
@timmer  # 相当于test1 = timmer(test1)
def test1():
    time.sleep(3)
    print("in the test1")
 
#直接执行test1函数   
test1()
 
#输出
in the test1
the func run time is 3.0002999305725098

 

【python】-- 装饰器、迭代器、生成器