【Python044--魔法方法:简单定制】
一、简单定制
基本要求:
-- 定制一个计时器的类
-- start和stop代表开始计时和停止计时
-- 假设计时器对象t1,print(t1)和直接调用t1均显示结果
-- 当计时器未启动或停止计时时,调用stop方法会给予温馨的提示
-- 两个计时器对象可以相加:t1 + t2
-- 只能使用提供的有限资源完成
=====================================================
程序编写之前需要了解一下资源(知识点)
-- 使用time模块的localtime方法获取时间
-- time.localtime()返回struct_time的时间格式
-- 表现你的类:__str__ 和 __repr__
解释:
返回struct_time时间格式
__str__ 和 __repr__
输入t1显示结果(显示字符串),要实现这个功能这时候就需要重写__str__ 和 __repr__方法
>>> class A:
def __str__(self):
return "I LOVE AI" >>> a = A()
>>> print(a)
I LOVE AI
>>> class B:
def __repr__(self):
return " I LOVE AI" >>> b = B()
>>> print(b)
I LOVE AI
>>> #要想实现print(对象)或者直接调用对象,就必须使用__str__ 和__repr__方法
整体程序的代码
import time as t class Mytimer():
def __init__(self):
#定义一个列表存放时间的单位,以便程序运行后输出的结果直接是带单位的结果:如:总共运行了:3秒
self.unit = ['年','月','天','小时','分钟','秒']
self.prompt = '未开始计时!'
self.lasted = []
#self.start = 0
self.begin = 0
#self.stop = 0
self.end = 0
#这里特别需要注意,方法名和属性名不能定义成同一个名字,否则属性会覆盖方法 #实现直接调用对象来输出内容
def __str__(self):
return self.prompt #__str__ 赋值给 __repr__
__repr__ = __str__ #两个对象相加
def __add__(self,other):
prompt = "总共运行了"
result = []
for index in range(6):
result.append(self.lasted[index]+other.lasted[index])
if result[index]:#如果result是空的话执行
prompt += (str(result[index])+self.unit[index])
return prompt #开始计时
def start(self):#self表示对象的引用
self.begin = t.localtime()
self.prompt = '提示:请先调用stop()停止计时'
print('计时开始...') #停止计时
def stop(self):
if not self.begin:
print("提示:请先调用start()进行计时!")
else:
self.end = t.localtime()
#结束计时时并进行计算,即对象.内部方法
self._clac()
print('计时结束!') #内部方法(_方法名),计算运行时间
def _clac(self):
#计算的结果放在一个列表里面
self.lasted = []
#定义一个提示的变量
self.prompt = '总共运行了'
#依次遍历localtime的索引
for index in range(6):
#用结束时间减去开始时间得到运行的时间,并把结果放到lasted[]列表内
self.lasted.append(self.end[index]-self.begin[index])
#把每一次计算的结果进行一次追加
if self.lasted[index]: #当lasted为0时就不会执行if内的语句,而是执行下一轮的循环
self.prompt += str(self.lasted[index])+self.unit[index] #运行时间+单位 #为下一轮计时初始化变量
self.begin = 0
self.end = 0 执行结果:
>>> t1 = Mytimer()
>>> t1.start()
计时开始...
>>> t1.stop()
计时结束!
>>> t1
总共运行了9秒
>>> t2 = Mytimer()
>>> t2.start()
计时开始...
>>> t2.stop()
计时结束!
>>> t2
总共运行了5秒
>>> t1+t2
'总共运行了14秒'
>>>
二、按照课中的程序,如果开始计时的时间是(2022年2月22日16:30:30)停止时间是(2025年1月23日15:30:30),那按照我们用停止时间减开始时间的计算方式就会出现负数,你应该对此做一些转换
import time as t class MyTimer: def __init__(self):
self.unit = ['年', '月', '天', '小时', '分钟', '秒']
self.borrow = [0, 12, 31, 24, 60, 60]
self.prompt = "未开始计时!"
self.lasted = []
self.begin = 0
self.end = 0 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("计时结束!") '''
|-- print ("end+++", self.end[index],"\nbegin---", self.begin[index]) 打印出来理解end[index],begin[index]
|-- for i in self.end:
print ("====",i) 打印看self.end是如何的运行的
''' # 内部方法,计算运行时间
def _calc(self):
self.lasted = []
self.prompt = "总共运行了"
for index in range(6):
temp = self.end[index] - self.begin[index]
print ("end+++", self.end[index],"\nbegin---", self.begin[index])
print("temp:",temp)
# for i in self.end:
# print ("====",i)
print("\n") # 低位不够减,需向高位借位
if temp < 0:
# 测试高位是否有得“借”,没得借的话向再高位借......
i = 1
while self.lasted[index - i] < 1:
self.lasted[index - i] += self.borrow[index - i] - 1
self.lasted[index - i - 1] -= 1
i += 1 self.lasted.append(self.borrow[index] + temp)
self.lasted[index - 1] -= 1
else:
self.lasted.append(temp) # 由于高位随时会被借位,所以打印要放在最后
for index in range(6):
if self.lasted[index]:
self.prompt += str(self.lasted[index]) + self.unit[index] # 为下一轮计时初始化变量
self.begin = 0
self.end = 0 t1 = MyTimer()
t1.start()
print("begin==",t1.begin)
t.sleep(5)
t1.stop()
#print("end==",t1.end)
print(t1) 执行结果:
计时开始...
begin== time.struct_time(tm_year=2018, tm_mon=11, tm_mday=2, tm_hour=16, tm_min=16, tm_sec=59, tm_wday=4, tm_yday=306, tm_isdst=0)
end+++ 2018
begin--- 2018
temp: 0 end+++ 11
begin--- 11
temp: 0 end+++ 2
begin--- 2
temp: 0 end+++ 16
begin--- 16
temp: 0 end+++ 17
begin--- 16
temp: 1 end+++ 4
begin--- 59
temp: -55 计时结束!
总共运行了5秒
三、相信大家已经意识到不对劲了:为毛一个月一定要31天?不知道又可能也是30天或者29天吗?(上一题我们的答案是假设一个月31天)
没错,如果要正确得到月份的天数,我们还需要考虑是否闰年,还有每月的最大天数,所以太麻烦了......如果我们不及时纠正,我们会在错误的道理上越走越远.......
所以,这一次,小甲鱼提出来了更加优秀的解决方案:用time模块的perf_counter()和process_time()来计算,其中perf_counter()返回计时器的精准时间(系统的运行时间);process_time()返回当前进程执行CPU的时间总和
题目:改进我们课堂中的例子,这次试用perf_counter()和process_time()作为计时器。另外增加一个set_timer()方法,用于设置默认计时器(默认是perf_counter(),可以通过此方法修改为process_time())
import time as t class Mytimer(): def __init__(self):
self.prompt = '未开始计时...'
self.begin = 0
self.end = 0
self.lasted = 0.0
self.default_timer = t.perf_counter def __str__(self):
return self.prompt __repr__ = __str__ def __add__(self, other):
result = self.lasted + other.lasted
prompt = '共运行了%0.2f秒'%result
return 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._clac()
print("计时结束!") def _clac(self):
self.lasted = self.end - self.begin
self.prompt = "总共运行了%0.2f秒"%self.lasted
print("end++",self.end,"\nbegin--",self.begin)
print("process_time=",t.process_time(),"perf_counter=",t.perf_counter()) self.begin = 0
self.end = 0 #设置计时器(time.per_counter()) 和(time.process_time())
def set_timer(self,timer):
if timer == 'process_time':
self.default_timer = t.process_time()
elif timer == 'per_counter':
self.default_timer = t.perf_counter()
else:
print("输入无效:请输入per_counter()或者process_time()") t1 = Mytimer()
t1.start()
t.sleep(5)
t1.stop()
print(t1) 执行结果:
开始计时...
end++ 79777.388179093
begin-- 79772.38780172
process_time= 0.040435 perf_counter= 79777.388454339
计时结束!
总共运行了5.00秒
四、既然咱都做到这一步,那不如深入一下,再次改进我们的代码,让它能够统计一个函数运行若干次的时间
要求一:函数调用的次数可以设置(默认是1000000次)
要求二:新增一个 timeing()方法,用于启动计时器
import time as t class Mytimer(): def __init__(self,func,number = 1000000):
self.propmt = '未开始计时...'
self.default_timer = t.perf_counter
self.number = number #函数调用的次数,默认是1000000
self.lasted = 0.0
self.func = func def __str__(self):
return self.propmt __repr__ = __str__ def __add__(self, other):
result = self.lasted+other.lasted
propmt = '共运行了%0.2f秒'%result
return propmt #内部方法,计算运行时间
def timer(self):
self.begin = self.default_timer()
for i in range(self.number):
self.func()
print("number=",self.number,"\nfunc=",self.func())
self.end = self.default_timer()
self.lasted = self.end - self.begin
self.propmt = '共运行了%0.2f秒'%self.lasted #设置计时器(perf_counter和process_time)
def set_timer(self,timer):
if timer == 'perf_counter':
self.default_timer = t.perf_counter()
elif timer == 'process_time':
self.default_timer = t.process_time()
else:
print("输入无效,请输入process_time或perf_counter") def test():
text = 'I love AI'
char = 'o'
for char in text:
pass t1 = Mytimer(test)
t1.timer()
print(t1) t2 = Mytimer(test,1000000)
t2.timer()
print(t2) print(t1+t2) 执行结果:
number= 1000000
func= None
共运行了0.30秒
number= 1000000
func= None
共运行了0.27秒
共运行了0.57秒
【Python044--魔法方法:简单定制】的更多相关文章
- python:类4——魔法方法(定制序列、迭代)、生成器、推导式
一.定制序列(容器类型) http://bbs.fishc.com/forum.php?mod=viewthread&tid=48793&extra=page%3D1%26filter ...
- 洗礼灵魂,修炼python(40)--面向对象编程(10)—定制魔法方法+time模块
定制魔法方法 1.什么是定制魔法方法 首先定制是什么意思呢?其实就是自定义了,根据我们想要的要求来自定义.而在python中,其实那些所谓的内置函数,内置方法,内置属性之类的其实也是自定义出来的,不过 ...
- python_魔法方法(二):算术运算
python2.2之后,对类和类型做了同意,将int().float().str().list().touple()这些BIF转换为工厂函数 >>> type(len) <cl ...
- python_魔法方法(五):描述符和定制序列
描述符(property的原理) 描述符(descripto),用一句话来解释,描述符就是某种特殊的类的实例指派给另一个类的属性.那么什么是特殊类型的类呢?就是至少要在这个类中定义__get__(). ...
- 【Python】 魔法方法
魔法方法 这个名字真的很中二有没有 = =(或者说翻译气息太浓了,作为一个学外语的看到这种真是想吐槽的不行..) 从形式上来说,在方法的名字前后个加上两条下划线的就是魔法方法了 .从功能上说,所有魔法 ...
- 零基础学习python_魔法方法(41-48课)(迭代器)
接下来这个为啥要叫魔法方法呢,额,这个嘛我是跟小甲鱼的视频取的名字一样的,因为会讲比较多杂的东西,有... 魔法方法详细阅读地址:http://bbs.fishc.com/thread-48793-1 ...
- with上下文管理 python魔法方法
with语法在Python里很常见, 主要的利好是使用代码更简洁. 常见的使用场景有: 1. 资源对象的获取与释放. 使用with可以简化try...finally ... 2. 在不修改函数代码的前 ...
- 面向对象相关概念与在python中的面向对象知识(魔法方法+反射+元类+鸭子类型)
面向对象知识 封装 封装的原理是,其成员变量代表对象的属性,方法代表这个对象的动作真正的封装是,经过深入的思考,做出良好的抽象(设计属性时用到),给出“完整且最小”的接口,并使得内部细节可以对外透明( ...
- Python学习笔记(七)——魔法方法
1.构造和析造 魔法方法就是被双下划线包围的方法 __init__()方法 __init__方法默认没有参数,返回值为none.类实例化对象需有明确的初始化步骤要重写函数 >>> c ...
随机推荐
- 记录一则完整的SPA(10g->11g)测试过程
生产端:Windows 2008 + Oracle 10.2.0.5 测试端:RHEL 6.5 + Oracle 11.2.0.4 需求:因为Oracle跨越大版本,优化器.新特性变动较多,需要进行S ...
- 日线做多,15min做空的情况收集
- C++调用openssl库生成RSA加密秘钥对
直接上代码.默认生成的是pkcs#1格式 // ---- rsa非对称加解密 ---- // #define KEY_LENGTH 1024 // 密钥长度 #define PUB_KEY_FILE ...
- js异步请求方式
一.使用defer 例: <script src="XXXXXX.js" defer></script> 二.使用promise 例: get('./moc ...
- python将目录切换为脚本所在目录
os.chdir(os.path.abspath(os.path.dirname(sys.argv[0])))
- Mysql版本java问题(com.mysql.cj.jdbc.Driver和com.mysql.jdbc.Driver)
老版本com.mysql.jdbc.Driver已弃用 String url1 = "jabc:mysql://127.0.0.1:3306/test"; String url1 ...
- ueditor上传图片配置成功,但是如何删除无用的图片
我使用ueditor作为富文本编辑器,配置已经好了,上传功能也好了.现在的问题是当使用ueditor上传图片的时候,选择了图片就立刻上传到指定的文件夹里,而后续即使没有保存该篇文章内容,即取消操作,图 ...
- datatable的点击事件
datatable的点击事件 在项目中遇到一个问题,在动态绑定到datatables上的数组,要是用table中的两个某一行中数据作为参数,通过鼠标点击进行获取,查阅官方文档得以解决: //首先定义一 ...
- Widget Factory (高斯消元解线性方程组)
The widget factory produces several different kinds of widgets. Each widget is carefully built by a ...
- PGPDesktop在win7环境下的安装和使用
PGPDesktop在win7环境下的安装和使用 PGP的简介 PGP(Pretty Good Privacy),是一个基于RSA公钥加密体系的邮件加密软件,它提供了非对称加密和数字签名,是目前非常流 ...