zoukankan      html  css  js  c++  java
  • 12-[函数进阶]-装饰器

    1.引入装饰器

      (1)函数版本

      (2)添加登录模块

    user_status = False
    def login():
        _username = "alex" #假装这是DB里存的用户信息
        _password = "123" #假装这是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 japan():
        print("----日韩专区----")
    
    
    def henan():
        login()
        print("----河南专区----")
    
    japan()
    henan()

    我现在有很多模块需要加认证模块,你的代码虽然实现了功能,但是需要更改需要加认证的各个模块的代码,这直接违反了软件开发中的一个原则“开放-封闭”原则,

    简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:

    • 封闭:已实现的功能代码块不应该被修改
    • 开放:对现有功能的扩展开放

       (3)登录函数中调用japan函数

     

      (4)装饰器原理

       

        

    2.语法糖:装饰器

    python解释器就会从上到下解释代码,步骤如下:

    1. def login(func): ==>将login函数加载到内存
    2. @login

    没错, 从表面上看解释器仅仅会解释这两句代码,因为函数在 没有被调用之前其内部代码不会被执行。

    从表面上看解释器着实会执行这两句,但是 @login 这一句代码里却有大文章, @函数名 是python的一种语法糖。

    3.通用装饰器

    user_status = False
    
    def login(fun):
    
        def inner(*args,**kwargs):      # 可变参数
            _username = "alex"
            _password = "123"
            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:
                fun(*args,**kwargs)        # 可变参数
     
        return inner

        

     4.两个装饰器

    def w1(func):
        print('---正在装饰--')
        def inner():
            print('---正在验证权限1--')
            func()
        return inner
    
    
    def w2(func):
        print('---正在装饰2--')
        def inner():
            print('---正在验证权限2--')
            func()
        return inner
    
    # 只要python解释器执行到了这个代码,那么就会自动的进行装饰,而不是等到调用的时候才装饰的
    @w2
    @w1
    def f1():
        print('---f1')
    
    f1()

       

     

     5.带参数装饰器

    • 在原有装饰器的基础上,设置外部变量,执行一次函数,获取它的返回值而已
    def func_arg(arg):
        def func(functionName):
            def func_in():
                print("---记录日志-%s-"%arg)
                functionName()
            return func_in
        return func
    
    #1.先执行func_arg("heihei")函数,这个函数return 的结果是func这个函数的引用
    #2.@func
    #3.使用@func对test进行装饰
    @func_arg('heihei')
    def test1():
        print('---testt')
    
    test1()
    ---记录日志-heihei-
    ---testt

    有什么用?

    # 认证函数
    def  auth(request,kargs):
        print("认证成功!")
    # 日志函数
    def log(request,kargs):
        print("日志添加成功")
    # 装饰器函数。接收两个参数,这两个参数应该是某个函数的名字。
    def Filter(auth_func,log_func):
        # 第一层封装,f1函数实际上被传递给了main_fuc这个参数
        def outer(main_func):
            # 第二层封装,auth和log函数的参数值被传递到了这里
            def wrapper(request,kargs):
                # 下面代码的判断逻辑不重要,重要的是参数的引用和返回值
                before_result = auth(request,kargs)
                if(before_result != None):
                    return before_result;
    
                main_result = main_func(request,kargs)
                if(main_result != None):
                    return main_result;
    
                after_result = log(request,kargs)
                if(after_result != None):
                    return after_result;
    
            return wrapper
        return outer
    # 注意了,这里的装饰器函数有参数哦,它的意思是先执行filter函数
    # 然后将filter函数的返回值作为装饰器函数的名字返回到这里,所以,
    # 其实这里,Filter(auth,log) = outer , @Filter(auth,log) =  @outer
    @Filter(auth,log)
    def f1(name,age):
    
        print("%s 正在连接业务部门1数据接口......"%name)
    
    # 调用方法
    f1("jack",18)
    #-----------------------------------------------
    运行结果:
    
    认证成功!
    jack 正在连接业务部门1数据接口......
    日志添加成功
    user_status = False #用户登录了就把这个改成True
    
    def login(auth_type): #把要执行的模块从这里传进来
        def auth(func):
            def inner(*args,**kwargs):#再定义一层函数
                if auth_type == "qq":
                    _username = "alex" #假装这是DB里存的用户信息
                    _password = "123" #假装这是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:
                        return func(*args,**kwargs) # 看这里看这里,只要验证通过了,就调用相应功能
                else:
                    print("only support qq ")
            return inner #用户调用login时,只会返回inner的内存地址,下次再调用时加上()才会执行inner函数
    
        return auth
    
    def home():
        print("---首页----")
    
    @login('qq')
    def america():
        #login() #执行前加上验证
        print("----欧美专区----")
    
    def japan():
        print("----日韩专区----")
    
    @login('weibo')
    def henan(style):
        '''
        :param style: 喜欢看什么类型的,就传进来
        :return:
        '''
        #login() #执行前加上验证
        print("----河南专区----")
    
    home()
    # america = login(america) #你在这里相当于把america这个函数替换了
    #henan = login(henan)
    
    # #那用户调用时依然写
    america()
    henan("3p")
    ---首页----
    user:alex
    pasword:123
    welcome login....
    ----欧美专区----
    only support qq 
    

      

  • 相关阅读:
    十个MySQL常用函数
    写给三十岁的自己
    EJS 模板引擎
    发送HTTP请求(GET,POST)
    路由模块化
    原生NodeJS封装Express路由
    Hook简介
    State Hook (useState)
    Effect hooks
    useContext
  • 原文地址:https://www.cnblogs.com/venicid/p/8431218.html
Copyright © 2011-2022 走看看