• Python基础学习笔记(14)装饰器


    Python基础学习(14)装饰器

    一、今日内容大纲

    • 装饰器 decorator
    • 装饰器的应用

    二、装饰器

    1. 开放封闭原则

      开放:对代码的拓展开放

      封闭:对源码的修改封闭

    2. 装饰器 decorator

      完全遵循开放封闭原则,是一个函数,本质上属于闭包 closure 的应用;在不改变原函数代码及调用方式的前提下,为其增加新的功能。

      现在,就一个测试函数执行效率的问题,我们对其进行讨论:

      • version 1: 写一些代码测试index()函数的执行效率。

        import time
        def index():
            time.sleep(2)  # 模拟网络延迟或代码效率
            print('welcome cnblogs.com')
        
        # print(time.time())
        # 格林威治时间 Greenwich Mean Time 返回1970纪元后的浮点秒数
        start_time = time.time()
        index()
        end_time = time.time()
        print(end_time - start_time)
        # summary: 如果要测试其他函数的代码效率,必须重新编写代码,效率低下。
        
      • version 2: 利用函数解决代码重复使用的问题。

        import time
        def index1():
            time.sleep(2)  # 模拟网络延迟或代码效率
            print('welcome cnblogs.com')
        
        def index2():
            time.sleep(3)  # 模拟网络延迟或代码效率
            print('enter the diary page')
        
        def timer(func):
            start_time = time.time()
            func()
            end_time = time.time()
            print(end_time - start_time)
        
        timer(index1)  # 修改了调用方式
        timer(index2)
        # summary:原来index函数源码没有变化,给原函数添加了一个测试执行效率的功能;但是不满足开放封闭原则,因为版本二修改了调用方式。
        
      • version 3: 着手调用方式问题,使装饰后的函数调用方式和原函数调用更加相似。

        import time
        def index1():
            time.sleep(2)  # 模拟网络延迟或代码效率
            print('welcome cnblogs.com')
        
        def index2():
            time.sleep(3)  # 模拟网络延迟或代码效率
            print('enter the diary page')
        
        def timer(func):
            def inner():
                start_time = time.time()
                func()
                end_time = time.time()
                print(end_time - start_time)
        
            return inner
        
        index1 = timer(index1)  # 多余项目
        index2 = timer(index2)  # 多余项目
        index1()
        index2()
        # summary:这就是最基础的装饰器,但是多了一项赋值运算,还需要优化
        
      • version 4: Python做了一个优化,提出了语法糖(Syntactic sugar)的概念,用来替代那项多余的赋值运算。

        import time
        # timer装饰器
        def timer(func):
            def inner():
                start_time = time.time()
                func()
                end_time = time.time()
                print(end_time - start_time)
        
            return inner
        
        @timer  # 等价于index1 = timer(index1) 读了两行
        def index1():
            time.sleep(2)  # 模拟网络延迟或代码效率
            print('welcome cnblogs.com')
        
        @timer  # 等价于index2 = timer(index2) 读了两行
        def index2():
            time.sleep(3)  # 模拟网络延迟或代码效率
            print('enter the diary page')
        
        index1()
        index2()
        # summary:在无传参的情况下,基本实现了开放封闭原则,但是如果被装饰函数有参数传输,又会出现问题。
        
      • version 5: 被装饰函数拥有返回值时的情况。

        import time
        # timer装饰器
        def timer(func):
            def inner():
                start_time = time.time()
                r = func()  # 实际的返回值在这里
                end_time = time.time()
                print(end_time - start_time)
                return r  # 将index1()返回值通过inner()返回
        
            return inner
        
        @timer  # 等价于index1 = timer(index1) 读了两行
        def index1():
            time.sleep(2)  # 模拟网络延迟或代码效率
            print('welcome cnblogs.com')
            return 666
        
        @timer  # 等价于index2 = timer(index2) 读了两行
        def index2():
            time.sleep(3)  # 模拟网络延迟或代码效率
            print('enter the diary page')
            return 777
        
        ret1 = index1()  # inner()的返回值要变成index1()的返回值
        ret2 = index2()
        print(ret1, ret2)
        # summary:通过inner()将index()返回值返回
        
      • version 6: 被装饰函数有参数传入时的情况。

        import time
        # 标准timer装饰器*******************
        def timer(func):
            def inner(*args, **kwargs):  # *代表聚合
                start_time = time.time()
                r = func(*args, **kwargs)  # *代表打散,相当于func(*(),**{})
                end_time = time.time()
                print(end_time - start_time)
                return r  # 将index1()返回值通过inner()返回
        
            return inner
        
        @timer  # 等价于index1 = timer(index1) 读了两行
        def index1(name):
            time.sleep(2)  # 模拟网络延迟或代码效率
            print(f"welcome 'cnblogs.com', {name}.")
            return 666
        
        @timer  # 等价于index2 = timer(index2) 读了两行
        def index2(name, title):
            time.sleep(3)  # 模拟网络延迟或代码效率
            print(f'{title}{name} enter the diary page')
            return 777
        
        ret1 = index1('太白')  # inner()的返回值要变成index1()的返回值
        ret2 = index2('纳钦', 'Dr.')
        print(ret1, ret2)
        
    3. 装饰器的标准形式

      # 标准版的装饰器
      def wrapper(f):
          def inner(*args, **kwargs):
              """添加额外功能:f()之前的装饰"""
              ret = f(*args, **kwargs)
              """添加额外功能:f()之后的装饰"""
              return ret
          return inner
      

    三、装饰器的应用:以博客园的登录为例

    # 装饰器的应用:登录认证
    # 这周的周末作业:模拟博客园登录,需要利用装饰器的认证功能
    login_status = dict(
        status=False,
        username=None
    )
    def get_users_info():
        users_info = {}
        with open(r'02 装饰器的应用users_info', encoding='utf-8') as file_handler:
            for line in file_handler:
                li = line.split('|')
                users_info.setdefault(li[0].strip(), li[1].strip())
        return users_info
    
    def login():
        users_info = get_users_info()
        # print(users_info)
        for i in range(3):
            username = input('username:')
            password = input('password:')
            if username in users_info and users_info[username] == password:
                login_status['status'] = True
                login_status['username'] = username
                return True
            else:
                print('The account password you entered is not correct.')
        return False
    
    
    def auth(func):
        def inner():
            if not login_status['status']:
                login()
            if login_status['status']:
                func()
            return
        return inner
    
    @auth
    def article():
        print('欢迎访问文章页面')
    
    @auth
    def comment():
        print('欢迎访问评论页面')
    
    @auth
    def dairy():
        print('欢迎访问评论页面')
    
  • 相关阅读:
    html和css简介;
    包装函数,面向切面的函数实现;
    RegExp
    javascript基础语法&5
    用Pyinstaller把Python3.7程序打包成可执行文件exe
    Idea下安装Lombok插件
    Moco框架jar下载地址
    安装时后的idea,项目不能运行,pom.xml文件不能下载到本地仓库,maven配置是正确的
    如何使用Git命令将项目从github或者服务器上克隆下来
    github怎么创建一个项目,怎么添加一个ssh-key的客户
  • 原文地址:https://www.cnblogs.com/raygor/p/13288781.html
Copyright © 2020-2023  润新知