丨游戏灬需要 发表于 2022-12-3 18:39:07

一个给代码运行计时的模块

原本想给自己的代码辅助用的(用于知道挂机运行很久后,代码运行到哪了),但因为后面没有需要运行那么长时间的代码而就没用这个模块了,所以就分享出来 ,也当做自己的一个云备份

'''
为代码添加个建议的实显信息条
可在一个运行时间很长的程序中 ,有个看得见的期望(相当于红绿灯中有了读秒)

导入方法:
    from infoBar import infoBar #infoBar是这个模块的名

启用示例:
    @infoBar
    def func():
      ...

    或↓
    with infoBar:
      ...

具体修改演示:
    参考if __name__ == '__main__':里的__useExample()
'''
from time import perf_counter as _perf_counter ,sleep as _sleep
from datetime import timedelta as _timedelta
from concurrent.futures import ThreadPoolExecutor as _ThreadPoolExecutor
from functools import wraps as _wraps


class _InfoBar:
    def __init__(self):
      # region 基础配置
      self.__enterNum = 0
      self.__refreshTime = 0.1
      self.__executor = _ThreadPoolExecutor(1)
      # endregion

      # region 一个简单就能实现的功能 ,可以让用户记录func内想知道的一些信息(将知道的信息带出来)
      self.shelve = {}
      # endregion

      # region 信息栏配置
      # region 信息数据
      self.__startTime = 0
      self.__defaultTitle = ''
      self.__title = self.__defaultTitle
      self.__defaultMsg = ''
      self.__msg = self.__defaultMsg
      self.__progressCur = 0
      self.__progressMax = 0
      # endregion

      self.__barFormat = '[{Time}]{title}{progress}:{msg}'

      self.__barValueDict = {
            'Time': lambda: f'{_timedelta(seconds=int(_perf_counter() - self.__startTime))}' ,
            'title': lambda: f'{self.__title}' ,
            'progress': lambda: f'({self.__progressCur / self.__progressMax:.2%})'
            if self.__progressMax else '' ,
            'msg': lambda: f'{self.__msg}' ,
      }
      # endregion

    def __del__(self):
      self.__executor.shutdown()

    def __enter__(self):
      self.__enterNum += 1
      if self.__enterNum == 1:
            self.__startTime = _perf_counter()
            # region 清空之前使用数据
            self.startSet()
            self.shelve.clear()
            # endregion
            self.__executor.submit(self.__timing)
      return self

    def __exit__(self ,exc_type ,exc_val ,exc_tb):
      self.__enterNum -= 1
      if self.__enterNum == 0:
            if exc_val is None:
                print(f'{self}\n' ,end='')

    def __call__(self ,func):
      @_wraps(func)
      def call(*args ,**kwargs):
            with self:
                return func(*args ,**kwargs)

      return call

    def __str__(self):
      text = self.__barFormat.format_map(
            {
                k: self.__barValueDict()
                for k in self.__barValueDict
                if k in self.__barFormat
            }
      )
      if len(text) > 100:
            text = text[:101] + '...'
      return text

    def __timing(self):
      while self.__enterNum:
            print(f'{self}\r' ,end='')
            _sleep(self.__refreshTime)

    def startSet(self ,defaultTitle: str = '' ,defaultMsg: str = '' ,refreshTime: int = 0.1):
      '''
      设置new的默认title和msg \n
      一般只在开头调用一次 ,要来描述最初情况下 ,这段func在做什么\n
      :param defaultTitle: 此func里默认的title值 ,用来描述这个函数最初情况下在做什么
      :param defaultMsg: 此func里默认的msg值 ,用来描述这个函数最初情况下所想知道的信息 ,一般不设置
      :param refreshTime: 设置刷新时间 ,一般不设置
      :return:
      '''
      if self.__enterNum == 1:
            self.__defaultTitle = defaultTitle
            self.__defaultMsg = defaultMsg
            self.__refreshTime = refreshTime
            self.new()

    def new(self ,title: str = ... ,msg: str = ... ,setPMax: int = 0 ,setPCur: int = 0):
      '''
      覆盖infoBar的实显信息\n
      注意:\n
      别企图用new直接代替chg \n
      因为那样会在使用进度百分比值时极大幅度拖累运行速度\n
      :param title: 设置初始"大概在做的事"的描述
      :param msg: 设置初始"具体关注的信息"
      :param setPMax: 设置初始"进度百分比"的分母值
      :param setPCur: 设置初始"进度百分比"的分子值,一般不设置
      :return:
      '''
      if self.__enterNum == 1:
            self.__title = self.__defaultTitle if title is ... else title
            self.__msg = self.__defaultMsg if msg is ... else msg
            self.__progressMax = setPMax
            self.__progressCur = setPCur
            print(f'{self}\r' ,end='')

    def msg(self ,msg: str = ... ,addPCur: int = 1 ,title: str = ...):
      '''
      修改infoBar的时显信息\n
      :param msg: 修改"具体关注的信息"
      :param addPCur: 在设置了(使用了)"进度百分比"时 ,增加其分子值
      :param title: 修改"当前在做的事" ,一般不修改
      :return:
      '''
      if self.__enterNum == 1:
            if msg is not ...: self.__msg = msg
            if self.__progressMax:
                self.__progressCur += addPCur
            if title is not ...: self.__title = title

    def pop(self ,title: str = ... ,msg: str = ...):
      '''
      弹出你所想要修改后记录的信息 \n
      如果没有记录这弹出的需求 \n
      则可以直接用new的方法代替 \n
      :param title: 修改"大概在做的事"的描述
      :param msg: 修改"具体关注的信息"
      :return:
      '''
      if self.__enterNum == 1:
            if title is not ...: self.__title = title
            if msg is not ...: self.__msg = msg
            print(f'{self}\n' ,end='')
            self.new()


infoBar = _InfoBar()
__all__ = [
    'infoBar'
]
if __name__ == '__main__':
    @infoBar
    def __useExample(arg1=10000000):
      infoBar.startSet('这里是使用示例')# 在开头设置new是title和msg的默认值 ,来说明整个func在最初做什么
      _sleep(2)
      infoBar.new('for i in arg1中' ,'' ,arg1)# 设置新的信息条来覆盖旧的信息条(没有设置的则为空)
      for item in range(arg1):
            infoBar.msg(f'修改需要注意的信息,如item的值:{item}')# 随着程序的运行 ,而修改你所需要关注的信息
      infoBar.pop('for i in arg1结束' ,f'记录出想要记录的信息例如item的值是{item}')# 在结束时 ,弹出你记录的完成结果
      _sleep(2)
      infoBar.new('测试结束' ,f'返回值是(arg1):{arg1}')# 可以在最后设置默认信息 ,在不同的结束能得知不同的情况
      return arg1


    # __useExample()

    # region 这里等于__useExample里的代码用with来运行
    with infoBar:
      arg1 = 10000000
      infoBar.startSet('这里是使用示例')# 在开头设置new是title和msg的默认值 ,来说明整个func在最初做什么
      _sleep(2)
      infoBar.new('for循环中' ,'' ,arg1)# 设置新的信息条来覆盖旧的信息条(没有设置的则为空)
      for item in range(arg1):
            infoBar.msg(f'修改需要注意的信息,如item的值:{item}')# 随着程序的运行 ,而修改你所需要关注的信息
      infoBar.pop('for i in arg1结束' ,f'记录出想要记录的信息例如item的值是{item}')# 在结束时 ,弹出你记录的完成结果
      _sleep(2)
      infoBar.new('测试结束' ,f'返回值是(arg1):{arg1}')# 可以在最后设置默认信息 ,在不同的结束能得知不同的情况
    # endregion

    pass
页: [1]
查看完整版本: 一个给代码运行计时的模块