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 

  

原文地址:https://www.cnblogs.com/venicid/p/8431218.html