zoukankan      html  css  js  c++  java
  • 函数之装饰器的使用

    nonlocal关键字

    num = 0
    def fn():
        global num  # L => G, 将局部名字与全局名字统一
        num = 20
    fn()
    print(num)
    
    def outer():
        # global num
        num = 0
        def inner():
            # 如果想在被嵌套的函数中修改外部函数变量(名字)的值
            nonlocal num  # 将 L 与 E(E中的名字需要提前定义) 的名字统一
            num = 10
            print(num)
        inner()
        print(num)
    outer()
    # print(num)
    

    装饰器

    '''
    装饰器:就是闭包(闭包的一个应用场景)
    	-- 把要被装饰的函数作为外层函数的参数通过闭包操作后返回一个替代版函数
    	
    优点:
    	-- 丰富了原有函数的功能
    	-- 提高了程序的可拓展性
    '''
    

    开放封闭原则 : 不改变调用方式与源代码上增加功能

    '''
    1.不能修改被装饰对象(函数)的源代码
    2.不能更改被修饰对象(函数)的调用方式
    '''
    
    # 1.0版本
    def fn():
        print('fn run')
    fn()
    
    # 2.0版本
    def fn():
        print('fn run0')
        print('fn run1')
        print('fn run2')
    fn()
    
    # 修改了源代码,没有更改调用方式,对外调用方式还是原来的,但功能要有所增加(开放)
    def fn():
        print('fn run0')
        print('fn run')
        print('fn run2')
    fn()
    
    # 更改了调用方式,没有修改原功能代码(封闭)
    def wrap(fn):
        print('fn run0')
        fn()
        print('fn run2')
    wrap(fn)
    
    

    装饰器的简单实现

    def outer(func):
        def inner():
            print("新增功能1")
            func()
            print("新增功能2")
        return inner
    
    def func():
        print("原有功能")
        
    func = outer(func)
    
    # 花瓶
    
    def vase():
        print('插花')
    vase()
    
    # 增加一个绘画后观赏功能:不满足开放封闭原则,修改了源代码
    def vase():
        print('插花')
        print('绘画:进行观赏')
    vase()
    
    # 增加一个绘画后观赏功能:不满足开放封闭原则,修改了调用方式
    def wrap(fn):
        vase()
        print('绘画:进行观赏')
    wrap(vase)
    
    # 虽然满足了开放封闭原则,但是出现了函数调用的死循环
    def fn():
        vase()
        print('绘画:进行观赏')
    vase = fn
    vase()
    
    # 了解:满足开放封闭原则,且可以达到装饰器的作用:拓展功能
    def vase():
        print('插花')
    tag = vase  # 暴露在全局:很容易被修改掉
    def fn():
        tag()
        print('绘画:进行观赏')
    vase = fn
    vase()
    
    
    def wrap(tag):
        def fn():
            tag()
            print('绘画:进行观赏')
        return fn
    vase = wrap(vase)
    vase()
    
    
    def vase():
        print('插花')
        
    # 下方的函数嵌套结构就是装饰器
    def wrap(tag):
        def fn():
            tag()  # 原有的vase
            print('绘画:进行观赏')
        return fn  # 拓展功能后的vase
    vase = wrap(vase)  # 将拓展功能后的功能函数重新赋值给vase
    
    
    vase()  # 功能拓展了,且调用方式不变
    

    装饰器语法糖

    def outer(func):
        def inner():
            print("新增功能1")
            func()
            print("新增功能2")
        return inner
    
    @outer
    def func():
        print("原有功能")
        
    # 总结:一个函数可以被任意一个相关装饰器装饰,也可以被任意几个装饰器装饰
    # 注:装饰的顺序会影响新增功能的执行顺序
    
    
    

    装饰有参有返的函数

    def outer(func):
        def inner(*args, **kwargs):
            print("新增功能1")
            result = func(*args, **kwargs)
            print("新增功能2")
            return result
        return inner
    
    @outer
    def func(*args, **kwargs):
        print("原有功能")
        return "原有结果"
    # 增加一个账号处理功能:3位及以上英文字符或汉字
    def check_usr(fn):
        def inner(usr, pwd):
            if not (len(usr) >= 3 and usr.isalpha()):
                print('账号验证失败')
                return False
            result = fn(usr, pwd)  # login
            return result
        return inner
    
    # 增加一个密码处理功能:6位及以上英文和数字
    def check_pwd(fn):
        def inner(usr, pwd):
            if not (len(pwd) >= 6 and pwd.isalnum()):
                print('密码验证失败')
                return False
            return fn(usr, pwd)
        return inner
    
    # 登录功能
    @check_usr  # login = check_usr(login) = inner
    @check_pwd
    def login(usr, pwd):
        if usr == 'abc' and pwd =='123qwe':
            print('登录成功')
            return True
        print('登录失败')
        return False
    
    res = login('abc', '123qwe')  # inner
    print(res)
    

    装饰器结合可变长参数

    # 增加一个账号处理功能:3位及以上英文字符或汉字
    def check_usr(fn):
        def inner(usr, pwd):
            if not (len(usr) >= 3 and usr.isalpha()):
                print('账号验证失败')
                return False
            result = fn(usr, pwd)  # login
            return result
        return inner
    
    # 登录功能
    @check_usr
    def login(usr, pwd):
        if usr == 'abc' and pwd =='123qwe':
            print('登录成功')
            return True
        print('登录失败')
        return False
    
    res = login('abc', '123qwe')  # inner
    print(res)
    
    def wrap(fn):
        def inner(*args, **kwargs):
            # print(args)
            # print(kwargs)
            result = fn(*args, **kwargs)
            print('新增功能')
            return result
    
        return inner
    
    
    @wrap
    def func(a, b, c, *, x, y, z):
        print(a, b, c, x, y, z)
        print('原有功能')
    
    
    func(1, 2, 3, x=10, y=20, z=30)
    

    有参装饰器

    def wrap(arg):
        def outer(func):
            def inner(*args, **kwargs):
                print("新增功能1")
                result = func(*args, **kwargs)
                print("新增功能2")
                return result
            return inner
    
    @wrap("装饰器参数")
    def func(*args, **kwargs):
        print("原有功能")
        return "原有结果"
    
    def outer(input_color):
        def wrap(fn):
            if input_color == 'red':
                info = '33[36;41mnew action33[0m'
            else:
                info = 'yellow:new action'
    
            def inner(*args, **kwargs):
                pass
                result = fn(*args, **kwargs)
                print(info)
                return result
            return inner
        return wrap  # outer(color) => wrap
    
    color = input('color: ')
    @outer(color)  # @outer(color) ==> @wrap  # func => inner
    def func():
        print('func run')
    
    func()
    

    登录认证案例

    is_login = False  # 登录状态
    
    def login():
        usr = input('usr: ')
        if not (len(usr) >= 3 and usr.isalpha()):
            print('账号验证失败')
            return False
        pwd = input('pwd: ')
        if usr == 'abc' and pwd =='123qwe':
            print('登录成功')
            is_login = True
        else:
            print('登录失败')
            is_login = False
    
    
    # 完成一个登录状态校验的装饰器
    def check_login(fn):
        def inner(*args, **kwargs):
            # 查看个人主页或销售功能前:如果没有登录先登录,反之可以进入其功能
            if is_login != True:
                print('你未登录')
                login()
            # 查看个人主页或销售
            result = fn(*args, **kwargs)
            return result
        return inner
    
    # 查看个人主页功能
    @check_login
    def home():
        print('个人主页')
    
    # 销售功能
    @check_login
    def sell():
        print('可以销售')
    
    home()
    

    wraps修改函数文档注释

    from functools import wraps
    def outer(func):
        @wraps(func)
        def inner(*args, **kwargs):
            '''装饰器文档注释'''
            func(*args, **kwargs)
        return inner
    
    @outer
    def func(*args, **kwargs):
        '''原有文档注释'''
        print("原有功能")
    
  • 相关阅读:
    Jenkins系列之二——centos 6.9 + JenKins 安装
    查看linux系统是运行在物理机还是虚拟机方法
    Java 的不可变类 (IMMUTABLE CLASS) 和 可变类 (MUTABLE CLASS)
    Java中的mutable和immutable对象实例讲解
    理解Java中的引用传递和值传递
    深入理解Java中的Clone与深拷贝和浅拷贝
    java Clone使用方法详解
    Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
    赏美-第[001]期-20190504
    赏美-第[000]期
  • 原文地址:https://www.cnblogs.com/fuwei8086/p/10665253.html
Copyright © 2011-2022 走看看