##简单定制
       ※基本要求:
          —定制一个计时器的类
          —start和stop方法代表启动计时和停止计时
          —假设计时器对象t1,print(t1)和直接调用t1均显示结果
          —当计时器未启动或已经停止计时,调用stop方法会给予温馨的提示
          —两个计时器对象可以进行相加:t1 + t2
          —只能使用提供的有限资源完成
            (公开的计数器模块很多,只要上网去找很容易找到类似的计时器的模块,只需要导入进去,会用里面的方法就可以了,但这样不是自己写的,达不到锻炼的目的,先做下演示:)

##你需要这些资源
       ※使用time模块的localtime方法获取时间
            (获取两次的时间,再相减接可以得到运行的时间)
          —扩展阅读:time 模块详解(时间获取和转换)

※time.localtime返回struct_time的时间格式

※表现你的类:__str__ 和 __repr__
            (如果需求去表现你的类,就像输入t1就直接输出总共运行多少时间,这就需要重写str和repr方法)

            (如上所示,__str__就是用在被打印的时候需要字符串的形式输出的时候,那么他就会找到__str__的魔法方法,然后把它返回的值给打印出来,相当于java 的toString方法,但直接输a,还是打印的是对象值,需要再次重写__repr__就可以直接输出字符串,如下:)


先完成基本计时功能:

import time as tclass MyTimer():# 开始计时def start(self):self.start = t.localtime()print("计时开始...")# 停止计时def stop(self):self.stop = t.localtime()self._calc()print("计时结束!")# 内部(私有)方法,计算运行时间def _calc(self):# 存差值self.lasted = []# 提示信息self.prompt = "总共运行了"# 只用那个时间元组的前6个元素for index in range(6):# 把他们的差值逐一添加到列表中self.lasted.append(self.stop[index] - self.start[index])self.prompt += str(self.lasted[index])print(self.prompt)

测试:


            (000005表示是每一项的差值,了解更多time模块请去time 模块详解(时间获取和转换))

完成计时基本功能后:完成输入t1和print(t1)都可以直接显示结果,那么就需要重写__str__和__repr__方法来实现

import time as tclass MyTimer():def __init__(self):# 用于人性化显示self.unit = ["年","月","天","小时","分钟","秒"]self.prompt = "未开始计时!"self.lasted = []#不要和方法名重复,否则会覆盖方法self.begin = 0self.end = 0# 重写str实现print(t1)输出结果def  __str__(self):return self.prompt# 两个都是一样的__repr__ = __str__# 实现两个对象可以相加def __add__(self,other):# 普通变量就好prompt = "总共运行了"result = []for index in range(6):result.append(self.lasted[index] + other.lasted[index])if result[index]:prompt +=(str(result[index])+self.unit[index])return prompt# 开始计时def start(self):self.begin = t.localtime()self.prompt ="提示:请先调用stop()停止计时!"print("计时开始...")# 停止计时def stop(self):if not self.begin:print("提示:请先调用start()进行计时!")else:self.end = t.localtime()self._calc()print("计时结束!")# 内部(私有)方法,计算运行时间def _calc(self):# 存差值self.lasted = []# 提示信息self.prompt = "总共运行了"# 只用那个时间元组的前6个元素for index in range(6):# 把他们的差值逐一添加到列表中self.lasted.append(self.end[index] - self.begin[index])if self.lasted[index]: #差值为0就不会进入self.prompt += str(self.lasted[index]) + self.unit[index]#为下一轮计时初始化变量self.begin = 0self.end = 0


##进阶定制
       ※如果开始计时的时间是(2022年2月22日16:30:30),停止时间是(2025年1月23日15:30:30),那按照我们用停止时间减开始时间的计算方式就会出现负数(3年-1月1天-1小时),你应该对此做一些转换。
       ※现在的计算机速度都非常快,而我们这个程序最小的计算单位却只是秒,精度是远远不够的。
##温故知新之习题
            0. 按照课堂中的程序,如果开始计时的时间是(2022年2月22日16:30:30),停止时间是(2025年1月23日15:30:30),那按照我们用停止时间减开始时间的计算方式就会出现负数,你应该对此做一些转换。
           答:

import time as tclass MyTimer:def __init__(self):self.unit = ['年', '月', '天', '小时', '分钟', '秒']self.borrow = [0, 12, 31, 24, 60, 60]self.prompt = "未开始计时!"self.lasted = []self.begin = 0self.end = 0def __str__(self):return self.prompt__repr__ = __str__def __add__(self, other):prompt = "总共运行了"result = []for index in range(6):result.append(self.lasted[index] + other.lasted[index])if result[index]:prompt += (str(result[index]) + self.unit[index])return prompt# 开始计时def start(self):self.begin = t.localtime()self.prompt = "提示:请先调用 stop() 停止计时!"print("计时开始...")# 停止计时def stop(self):if not self.begin:print("提示:请先调用 start() 进行计时!")else:self.end = t.localtime()self._calc()print("计时结束!")# 内部方法,计算运行时间def _calc(self):self.lasted = []self.prompt = "总共运行了"for index in range(6):temp = self.end[index] - self.begin[index]# 低位不够减,需向高位借位 if temp < 0:# 测试高位是否有得“借”,没得借的话向再高位借......i = 1while self.lasted[index-i] < 1:self.lasted[index-i] += self.borrow[index-i] - 1self.lasted[index-i-1] -= 1i += 1self.lasted.append(self.borrow[index] + temp)self.lasted[index-1] -= 1else:self.lasted.append(temp)# 由于高位随时会被借位,所以打印要放在最后for index in range(6):if self.lasted[index]:self.prompt += str(self.lasted[index]) + self.unit[index]# 为下一轮计时初始化变量self.begin = 0self.end = 0

1. 相信大家已经意识到不对劲了:为毛一个月一定要31天?不知道有可能也是30天或者29天吗?(上一题我们的答案是假设一个月31天)

没错,如果要正确得到月份的天数,我们还需要考虑是否闰年,还有每月的最大天数,所以太麻烦了……如果我们不及时纠正,我们会在错误的道路上越走越远……

所以,这一次,小甲鱼提出了更优秀的解决方案(Python官方推荐):用 time 模块的 perf_counter() 和 process_time() 来计算,其中 perf_counter() 返回计时器的精准时间(系统的运行时间); process_time() 返回当前进程执行 CPU 的时间总和。

题目:改进我们课堂中的例子,这次使用 perf_counter() 和 process_time() 作为计时器。另外增加一个 set_timer() 方法,用于设置默认计时器(默认是 perf_counter(),可以通过此方法修改为 process_time())。
           答:

import time as tclass MyTimer:def __init__(self):self.prompt = "未开始计时!"self.lasted = 0.0self.begin = 0self.end = 0self.default_timer = t.perf_counterdef __str__(self):return self.prompt__repr__ = __str__def __add__(self, other):result = self.lasted + other.lastedprompt = "总共运行了 %0.2f 秒" % resultreturn prompt# 开始计时def start(self):self.begin = self.default_timer()self.prompt = "提示:请先调用 stop() 停止计时!"print("计时开始...")# 停止计时def stop(self):if not self.begin:print("提示:请先调用 start() 进行计时!")else:self.end = self.default_timer()self._calc()print("计时结束!")# 内部方法,计算运行时间def _calc(self):self.lasted = self.end - self.beginself.prompt = "总共运行了 %0.2f 秒" % self.lasted# 为下一轮计时初始化变量self.begin = 0self.end = 0# 设置计时器(time.perf_counter() 或 time.process_time())def set_timer(self, timer):if timer == 'process_time':self.default_timer = t.process_timeelif timer == 'perf_counter':self.default_timer = t.perf_counterelse:print("输入无效,请输入 perf_counter 或 process_time")

2. 既然咱都做到了这一步,那不如再深入一下。再次改进我们的代码,让它能够统计一个函数运行若干次的时间。
           要求一:函数调用的次数可以设置(默认是 1000000 次)
           要求二:新增一个 timing() 方法,用于启动计时器

>>> ================================ RESTART ================================
>>>
>>> def test():text = "I love FishC.com!"char = 'o'if char in text:pass>>> t1 = MyTimer(test)
>>> t1.timing()
>>> t1
总共运行了 0.27 秒
>>> t2 = MyTimer(test, 100000000)
>>> t2.timing()
>>> t2
总共运行了 25.92 秒
>>> t1 + t2
'总共运行了 26.19 秒'

答:

import time as tclass MyTimer:def __init__(self, func, number=1000000):self.prompt = "未开始计时!"self.lasted = 0.0self.default_timer = t.perf_counterself.func = funcself.number = numberdef __str__(self):return self.prompt__repr__ = __str__def __add__(self, other):result = self.lasted + other.lastedprompt = "总共运行了 %0.2f 秒" % resultreturn prompt# 内部方法,计算运行时间def timing(self):self.begin = self.default_timer()for i in range(self.number):self.func()self.end = self.default_timer()self.lasted = self.end - self.beginself.prompt = "总共运行了 %0.2f 秒" % self.lasted# 设置计时器(time.perf_counter() 或 time.process_time())def set_timer(self, timer):if timer == 'process_time':self.default_timer = t.process_timeelif timer == 'perf_counter':self.default_timer = t.perf_counterelse:print("输入无效,请输入 perf_counter 或 process_time")

学习完这一节课后,我想告诉大家一件事,其实,关于 Python 代码优化你需要知道的最重要问题是,决不要自己编写计时函数!!!!!

为一个很短的代码计时都很复杂,因为你不知道处理器有多少时间用于运行这个代码?有什么在后台运行?小小的疏忽可能破坏你的百年大计,后台服务偶尔被 “唤醒” 在最后千分之一秒做一些像查收信件,连接计时通信服务器,检查应用程序更新,扫描病毒,查看是否有磁盘被插入光驱之类很有意义的事。在开始计时测试之前,把一切都关掉,断开网络的连接。再次确定一切都关上后关掉那些不断查看网络是否恢复的服务等等。

接下来是计时框架本身引入的变化因素。Python 解释器是否缓存了方法名的查找?是否缓存代码块的编译结果?正则表达式呢? 你的代码重复运行时有副作用吗?不要忘记,你的工作结果将以比秒更小的单位呈现,你的计时框架中的小错误将会带来不可挽回的结果扭曲。

Python 社区有句俗语:“Python 自己带着电池。” 别自己写计时框架。Python 具备一个叫做 timeit 的完美计时工具。

或许你现在怨恨我为什么不早点说,但如果你在这节课的折腾中已经掌握了类的定制和使用,那我的目的就达到了。接下来,请认真阅读更为专业的计时器用法及实现源码:Python扩展阅读:timeit 模块详解(准确测量小段代码的执行时间),

魔法方法:简单定制+习题复习相关推荐

  1. python入门——P47魔法方法:定制序列

    容器类型的协议 希望容器不可变,则只需定义__len_()和__getitem_()方法 如果希望容器可变,除了上面两个,还需要__setitem_()和__delitem_()两个方法 编写一个不可 ...

  2. python_魔法方法(二):算术运算

    python2.2之后,对类和类型做了同意,将int().float().str().list().touple()这些BIF转换为工厂函数 >>> type(len) <cl ...

  3. python魔法方法_python_魔法方法(二):算术运算

    python2.2之后,对类和类型做了同意,将int().float().str().list().touple()这些BIF转换为工厂函数 >>>type(len) >> ...

  4. Python基础——魔法方法(一)

    文章目录 魔法方法 构造和析构 算数运算 算数操作符 反运算 增量赋值运算 一元操作符 属性访问 魔法方法 前面在介绍类和对象时,已经接触过Python常用的魔法方法,那么什么是魔法方法呢? 魔法方法 ...

  5. Python-面向对象-魔法方法(未完待续)

    目录 一.属性相关的魔法方法 (1) __getattribute__ (2)__getattr__ (3)__setattr__ (4)__delattr__ 二,容器魔法方法 (1)__len__ ...

  6. python 类 对象 魔法方法概念+习题

    类 对象 类 对象是c++和java中都有的内容,python定义类的简单语法如下: class 类名: -类变量或者方法 Python 的类定义有点像函数定义,都是以冒号:作为类体的开始,以统一缩进 ...

  7. python私人定制_手把手教你学python第十五讲(魔法方法续私人“定制”)

    python无处不对象的深刻理解 前面写了这么多,我觉得有必要从一个大的层面,也就是OO来看问题的本质.只要你调用对象的语法是合乎python的习惯的,那就是可以的,我们以前从来没有像下面这么写过,对 ...

  8. 简单定制统信UOS镜像的方法

    关于简单定制统信UOS镜像的方法 一:原因和目的 原因:由于目前统信的UOS系统装好之后第三方软件集成度较低,用户拿到手之后不能做到开箱即用,需要安装各类软件,用户体验不够友好. 目的:将需要预安装的 ...

  9. Python简单魔法方法

    说到魔法方法可能和我一样是小白的人没什么印象,但是如果说到Python 类的构建大家都应该能想到下面的函数 class _():def __init__(self):....... 其实看似简单的类定 ...

最新文章

  1. pip更换国内镜像源
  2. 火灾检测、人流量统计… 这个开源项目太香了!
  3. 实现linux作为server时与windows间的数据同步
  4. 天猫总裁靖捷回答了今年双11的热点问题
  5. 前端编程提高之旅(六)----backbone实现todoMVC
  6. CodeForces - 1031B Curiosity Has No Limits(思维)
  7. local tomcat 找不到springmvc里的包_唰唰的手撕一个简单的Spring Mvc 框架
  8. Atitit  项目界面h5化静态html化计划---vue.js 把ajax获取到的数据 绑定到表格控件 v2 r33.docx
  9. linux 5.8 设备的mac地址与预想的不符 已忽略,解决“eth0设备的MAC 址与预想的不符,忽略”...
  10. Excel VBA VBA去重复的几种方法
  11. php小程序秒抢高并发,微信小程序的10个请求并发限制的优化消息!!!
  12. 计算机应用精华系统性整理
  13. 豆瓣电影top250信息爬取
  14. 329、微信账户体系科普:什么是UnionId、OpenId与wxopenid?
  15. 视频号还是直播?2021年微信财富密码预言
  16. 小米路由器的服务器无响应怎么回事,小米路由器常见问题与解决方法(高级功能) | 192路由网...
  17. 自定义函数求圆和圆柱体的表面积
  18. Redis集群使用指南
  19. Android 虚拟按键隐藏或显示之后共享元素动画异常解决方案
  20. ntag213和215有什么区别_Ntag213、Ntag215、Ntag216电子标签

热门文章

  1. 库卡机器人emd价格_KUKA库卡机器人备件
  2. ARKit之路-AR截屏
  3. VS中MessageBox与AfxMessageBox用法与区别
  4. 【 盒模型】css盒模型学习
  5. VSCode 代码有的提示不能默认选中第一项问题
  6. Object类11种方法
  7. 骗补刷量 黑产变现|短视频及直播行业的暗流涌动...
  8. 【Python基础知识库】Python中字符串和字节串的区别
  9. 局域网ip部署web网站
  10. 【教学】图像分类算法中的召回率recall、精准率precision和f1score得分等计算。