• 函数之装饰器的使用


    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("原有功能")
    
  • 相关阅读:
    定义一个Dog类,它和静态数据成员Dogs记录Dog的个体数目。静态成员函数GetDogs用来存取Dogs。设计并测试这个类--简单
    互联网无插件直播流媒体服务器方案EasyNVR下载新的软件执行程序,出现“invalid license”字样是什么意思?
    视频流媒体服务器RTSP拉流、RTMP推流方案EasyNVR如何实现视频转推其他直播间?
    视频流媒体服务器RTSP拉流、RTMP推流流媒体服务器授权方案之加密机运行后无法授权问题解决
    RTSP安防网络摄像头/海康大华硬盘录像机网页无插件直播之EasyNVR流媒体服务器系列产品直播延时问题解析
    海康大华网络摄像头RTSP_Onvif网页无插件直播流媒体服务器EasyNVR录像版设定录像文件存储位置的方法解析
    同一路摄像头视频流接入RTSP_Onvif网页无插件直播流媒体服务器EasyNVR与其他平台播放视频有差异的原因分析
    RTSP_Onvif安防摄像头直播流媒体服务器EasyNVR产品调用接口出现"Unauthorized"问题的解决方法
    安防摄像头RTSP/Onvif协议网页无插件直播视频流媒体服务器EasyNVR录像回看质量的影响因素有哪些?
    海康、大华等网络摄像头RTSP_Onvif网页无插件直播流媒体服务器EasyNVR在内网环境下,设备不在线问题处理
  • 原文地址:https://www.cnblogs.com/fuwei8086/p/10665253.html
Copyright © 2020-2023  润新知