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:\Python\Python Project\day20\lianjia.html',
                 r'D:\Python\Python Project\day21\lianjia.html')
    
  2. 拷贝目录

    # shutil.copytree(old_path, new_path,
    #                 ignore=shutil.ignore_patterns('*.pyc'))
    # ignore=shutil.ignore_patterns('*.py') 表示不要所有的py文件
    shutil.copytree(r'D:\Python\Python Project\day21\day09',
                    r'D:\Python\Python Project\day21\day09.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')
      
posted @ 2020-07-19 22:00  Raigor  阅读(132)  评论(0)    收藏  举报