装饰器理解这篇博客看完你就懂了

这一生的挚爱 提交于 2020-03-04 18:42:11
  1. 定义(如何理解装饰器):装饰器本生是闭包函数的一种应用,是指在不改变原函数的情况下为原函数添加新的功能的一个函数。它把被装饰的函数作为外层函数的参数传入装饰器,通过闭包操作后返回一个替代版函数。
  2. 遵循的原则: 开放封闭原则------在不改变调用方式和源代码的情况下,增加新功能。
    1. 不能改变被修饰对象(函数(后面还会对类进行装饰))的源代码(封闭)
    2. 不能改变被修饰对象(函数(以后还会对类进行装饰))的调用方式,且能达到增加功能的效果。(开放)
  3. 优点:
    1. 丰富了原函数的功能
    2. 提高了程序的可拓展性
  4. 装饰器的简单实现:
# 无参装饰器公式:
def fn():
    print('原功能')
    
def outer(fn):
    def inner():
        print('新功能1')
        fn()
        print('新功能2')
    return inner
fn = outer(fn1)
print(fn())
"""
案例分析: 定义一个打印插花的函数,为其前面添加绘画功能,后面添加观赏功能。
如何一步一步完成完整的装饰器函数。
"""

def vase():
    print('插花')
    
    
def wrap():
    tag = vase  # 此时的vase 是在wrap()还没有运行结束的时候,wrap没有返回值,所以tag被赋值的是vase原先的值。
    
    def outer():
        print('绘画')
        tag()  # 原先的vase
        print('观赏')
    
    return outer  # wrap()函数返回的是outer函数的地址空间


vase = wrap()  # vase = outer

vase()

 上述代码,存在一个缺陷,就是没有写活,没办法将装饰器用在其他函数上,对于无参装饰器的正确的姿势应该如下:

def vase():
    print('插花')    

def wrap(fn):
    def outer():
        print('绘画')
        fn()  # 原先的vase
        print('观赏')
    
    return outer


vase = wrap(vase)  # vase = outer()

vase()

那么如何让代码更简洁? python 提供一种语法糖,可以让代码看起来更简洁

def wrap(fn):
    def outer():
        print('绘画')
        fn()  # 原先的vase
        print('观赏')
    
    return outer

@wrap  # 此语法糖形式,实际上就是完成了 vase = wrap(vase)操作 = outer
def vase():
    print('插花')


print(vase())

下面来看看如何进行多层装饰:(多层装饰注意一个顺序问题,执行时是从上向下执行,返回操作的时候是一层一层跳出)

def wrap1(fn):
    def outer():
        print('绘画')
        fn()  # 原先的vase
        print('观赏')
    
    return outer


def wrap2(fn):
    def outer():
        print('购买')
        fn()  # 原先的vase
    
    return outer

@wrap2
@wrap1
def vase():
    print('插花')


vase()

# 购买
# 绘画
# 插花
# 观赏


@wrap1
@wrap2
def vase():
    print('插花')


vase()

# 绘画
# 购买
# 插花
# 观赏

  5.有参有返的装饰器

def wrap(func):
    def inner(*args, **kwargs):  # 此处 *args  (接收所有位置参数) 接收(a,b,c)以元组形式存储,kwargs  (接收所有关键字参数) 则是接收{x:4,y:5,z:6}存成字典形式
        print('新功能1')
        res = func(*args, **kwargs)
        print('新功能2')
        return res

    return inner


@wrap
def fn(a, b, c, *, x, y, z):
    print(a, b, c, x, y, z)


re = fn(1, 2, 3, x=4, y=5, z=6)
print(re)

# 新功能1
# 1 2 3 4 5 6
# 新功能2
# None   返回值是None 因为函数fn本身无return

 案例:在原登录功能下增加账号验证和密码验证功能

# 增加一个账号安全处理功能:3位英文字母或汉字
def check_pwd(fn):
    def inner(usr, pwd):
        if not (len(pwd) >= 6 and usr.isalpha()):
            print('账号认证失败')
            return False
        return fn(usr, pwd)
    
    return inner


# 增加一个密码处理功能 : 6位以上英文和数字组合

def check_usr(fn):  # login = check_usr(login) = inner
    def inner(usr, pwd):
        if not (len(usr) >= 3 and usr.isalnum()):
            print('密码认证失败')
            return False
        return fn(usr, pwd)
    
    return inner


@check_usr  # login = inner   # 语法糖 谁现在下面谁先装功能,套在最外面(上面的)的是最先执行的
@check_pwd
# 登录功能
def login(usr, pwd):
    if usr == 'qwe' and pwd == '123123':
        print('登录成功')
        return True
    print('登录失败')
    return False

res1 = login('asdd', '123')
res2 = login('as', '123123')
res3 = login('qwe', '123')
res4 = login('qwe', '123123')
print(res1)
print(res2)
print(res3)
print(res4)

# 账号认证失败
# 密码认证失败
# 账号认证失败
# 登录成功
# False
# False
# False
# True

带参装饰器(def wrap(参数们))

# 通过带参装饰器,实现增加颜色选择功能
def color_choice(color_inp):
    def wrap(fn):
        if color_inp == 'red':
            info = 'red:new action'
        else:
            info = 'yellow:new action'
        
        def inner(*args, **kwargs):
            res = fn(*args, **kwargs)
            print(info)
            return res
        
        return inner  # wrap(fn) 返回的是 inner函数对象(地址)
    
    return wrap  # color_choice 返回的是 wrap函数对象 color_choice(color_inp)() => wrap() => res


color_inp = input('color:')


@color_choice(color_inp)
def func():
    print('func run ')


func()

案例:查看个人主页前的登录状态验证

is_login = False


def login():
    usr = input('usr:').lower()
    if not (len(usr) >= 3 and usr.isalnum()):
        print('密码认证失败')
        return False
    pwd = input('pwd:')
    if usr == 'qwe' and pwd == '123123':
        print('登录成功')
        is_login = True
    else:
        print('登录失败')
        is_login = False


# 完成一个登录状态校验的装饰器
def check_login(fn):
    def inner(*args, **kwargs):
        if is_login != True:
            print('你未登录')
            login()
        res = fn(*args, **kwargs)
        return res
    return inner


# 查看个人主页功能
@check_login
def homepage():
    print('个人主页')

@check_login
# 销售功能
def sell():
    print('销售页面')
    
homepage()

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!