• Python基础学习笔记(20)递归详解 shutil 模块 logging 模块


    Python基础学习(20)递归详解 shutil 模块 logging 模块

    一、今日大纲

    • 递归详解
    • shutil 模块
    • logging 模块

    二、递归详解

    针对之前的斐波那契数列Fibonacci Sequence问题,经过不断思考,运用递归、生成器、循环等方法,总结出了以下四种方法:

    • 递归方法1:

      # 递归方法1
      @log_interval
      def Fibonacci(n):
          def inner(args):
              if args == 1 or args == 0:
                  return 1
              return inner(args - 1) + inner(args - 2)
      
          r = inner(n)
          return r
      
    • 递归方法2:

      # 递归方法2
      @log_interval
      def Fibonacci(n):
          def inner(args, a=1, b=1):
              if args == 0:
                  return a
              a, b = b, a + b
              return inner(args - 1, a, b)
      
          return inner(n)
      
    • 循环方法:

      # 非递归方法
      def Fibonacci(n):
          a = 1
          b = 1
          for i in range(n):
              a, b = b, a + b
          return a
      
    • 生成器方法

      # 生成器方法
      def Fibonacci(n):
          i = 0
      
          def inner(args):
              a = 1
              yield a
              b = 1
              for i in range(args):
                  a, b = b, a + b
                  yield a
      
          for i in inner(n):
              pass
          return i
      

    为了计算比较下列方法的时间复杂度,设计了如下装饰器来比较四种方法的效率。

    def read_dir(dirname):
        # if os.listdir(dirname) == []:
        #     return
        for i in os.listdir(dirname):
            if os.path.isfile(os.path.join(dirname, i)):
                print(i)
            if os.path.isdir(os.path.join(dirname, i)):
                read_dir(os.path.join(dirname, i))
    

    嵌上装饰器后,我们分别向四个函数传入了不同的参数,下表是每个方法传输的不同参数以及所用时间:

    传入参数 返回时间
    递归方法1 30 interval: 0.4075314998626709
    递归方法2 50 interval: 0.0010001659393310547
    循环方法 50000 interval: 0.044003963470458984
    生成器方法 50000 interval: 0.04400515556335449

    根据上表我们可知,效率方面生成器方法 ≈ 循环方法 > 递归方法2 >> 递归方法1

    递归方法1:将一个问题通过分治法分解成两个子问题,调用函数的次数也必将是最多的,所以其效率理所应当归为最低;

    递归方法2:将方法1返回的两个子问题集合成了一个问题,大幅度地减少了函数的调用次数,性能产生了很大的提升,但是由于递归自身方法的限制,效率仍然不高;

    循环方法:利用了和递归方法2同样的思想,有点类似于链表头插法保存Pre-NodeNode的思想,不断向下滚动生成所需的结果,由于只有一层循环,所以效率非常高。

    生成器方法:利用刚刚学习的yield构建生成器的方法,也可以只需要一层循环实现斐波那契数列的计算,本质上也属于循环方法,效率和上面的循环方法基本一致。

    三、shutil 模块

    shutil 模块对文件和文件集合提供了许多高级操作,特别是提供了支持文件复制和删除的函数。

    1. 拷贝文件

      # `shutil.copy2(old_path, new_path)`
      shutil.copy2(r'D:PythonPython Projectday20lianjia.html',
                   r'D:PythonPython Projectday21lianjia.html')
      
    2. 拷贝目录

      # shutil.copytree(old_path, new_path,
      #                 ignore=shutil.ignore_patterns('*.pyc'))
      # ignore=shutil.ignore_patterns('*.py') 表示不要所有的py文件
      shutil.copytree(r'D:PythonPython Projectday21day09',
                      r'D:PythonPython Projectday21day09.bak',
                      ignore=shutil.ignore_patterns('*.py'))
      
    3. 删除目录(慎用)

      # shutil.rmtree(path, ignore_errors=True)  # ignore_errors=True 表示无视删除的提示(比如文件正在占用)
      shutil.rmtree('day09', ignore_errors=True)
      
    4. 移动文件/目录

      # shutil.move(old_path, new_path, copy_function=shutil.copy2)
      
    5. 获取磁盘使用空间

      total, used, free = shutil.disk_usage('c:\')
      print('当前磁盘共: %iGB, 已使用: %iGB, 剩余: %iGB'
            %(total / 1073741824, used / 1073741824, free/1073741824))
      # 1073741814 = 1024^3
      
      # %i是一种表十进制的占位符和%d基本没有区别(找到了之后会写在这里)
      
    6. 压缩文件

      # shutil.make_archive(compressed_file_path, 'zip', file_path)
      shutil.make_archive('day09_z', 'zip', 'day09.bak')
      
    7. 解压文件

      # shutil.unpack_archive(compressed_file_path, 'zip', file_path)
      shutil.unpack_archive('day09_z.zip', 'day09_unz', 'zip')
      

    四、logging 模块

    1. 日志的意义

      • 用来排除错误
      • 用来做数据分析
    2. 日志的意义——以网络购物商城为例

      一个项目需要构建一个数据库存放足够重要的内容;而还有一些相对来说没那么重要的内容,我们没必要将它们放入数据库,这时,本地构建日志就成了我们的最佳选择。

      如购物商城中:

      数据库:什么时间买了什么商品、购物车中放置了哪些商品存入;

      本地日志:用户登录时间、搜索记录、用户关闭时间、浏览商品清单等;

      比如我们拥有 10W 客户,每天有 1W 条购买记录需要存放在数据库中,每天就会有10W+ 条和购买相关的信息由于数据库容量限制和网络传输限制,需要存放在本地日志中;我们进行数据分析、操作审计、排查BUG等情况下,均需要检查日志记录的情况,所以记录日志对于项目来说非常重要;而记录日志,就需要 logging 模块。

    3. 日志信息的等级

      由于需要记录的信息众多,所以我们必须要对记录的内容进行重要性排序,logging 模块为我们提供了以下五种重要性:

      # 输出内容是有等级的,重要性从上至下依次升高:默认处理warning级别以上的所有信息
      # logging.debug('debug message')
      # logging.info('info message')
      # logging.warning('warning message')
      # logging.error('error message')
      # logging.critical('critical message')
      

      logging 模块默认处理warning级别以上的所有信息,而我们可以通过logging.basicConfig(level=logging.DEBUG)吧重要性调整为DEBUG等级,调整为其它等级同理。

    4. 日志的设置

      • 输出到屏幕

        logging.basicConfig(
            format='%(asctime)s - %(name)s - %(levelname)s[line : %(lineno)d] -%(module)s:  %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S %p')
        
        logging.warning('warning test')  # 2020-07-18 21:22:00 PM - root - WARNING[line : 66] -03 logging 模块:  warning test
        
      • 输出到文件

        logging.basicConfig(
            format='%(asctime)s - %(name)s - %(levelname)s[line : %(lineno)d] -%(module)s:  %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S %p',
            filename='tmp.log',
            level=logging.DEBUG,
            filemode='a'
        )
        
        logging.debug('debug test')
        logging.warning('warning test1')
        logging.warning('warning test2')
        
      • 同时向屏幕和文件上输出

        fh = logging.FileHandler('tmp.log', encoding='utf-8')  # 定义log的编码类型和文件路径
        sh = logging.StreamHandler()
        logging.basicConfig(
            format='%(asctime)s - %(name)s - %(levelname)s[line : %(lineno)d] -%(module)s:  %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S %p',
            level=logging.DEBUG,
            # handlers=[fh, sh]
        )
        
        logging.warning('warning test1')
        logging.warning('warning test2')
        logging.warning('warning test3')
        
      • 定时/定长记录日志

        import time
        from logging import handlers
        # 按照大小做切割,每个日志1024字节,每五个替换一次
        rh = handlers.RotatingFileHandler('myapp.log', maxBytes=1024, backupCount=5)
        # 按时间切,按秒切,只记录距今6s的记录
        th = handlers.TimedRotatingFileHandler(filename='x2.log', when='s', interval=6, encoding='utf-8')
        sh = logging.StreamHandler()
        logging.basicConfig(
            handlers=[rh, sh, th],
            format='%(asctime)s - %(name)s - %(levelname)s[line : %(lineno)d] -%(module)s:  %(message)s',
            datefmt="%Y-%m-%d %H:%M:%S %p",
            level=logging.DEBUG
        )
        
        for i in range(19999):
            time.sleep(0.5)
            logging.warning('warning test1')
        
  • 相关阅读:
    移除HTML5 input在type="number"时的上下小箭头
    JQUERY 实现加入收藏夹功能
    发现移动端在uc浏览器上会放大bug,解决此bug的方法!
    HTML 定时页面跳转
    Some Commands I Used Frequently
    Some Life Tricks I Noticed
    几种工厂模式的区别
    大型DELETE(删除大量数据)的一种解决方案
    笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-10 可编程对象
    笔记-Microsoft SQL Server 2008技术内幕:T-SQL语言基础-09 事务和并发
  • 原文地址:https://www.cnblogs.com/raygor/p/13341631.html
Copyright © 2020-2023  润新知