通过Python实现定时器和利用魔法方法改善友好交互

来源:互联网 发布:淘宝众筹 淘宝怎么不管 编辑:程序博客网 时间:2024/05/01 05:13

           实现Python的定时器是需要用到time库,其中需要调用的是localtime()方法,返回的是struct_time的时间格式,实际中只取前六位(年、月、日、时、分、秒)来达到实现计时的目的。今天的博文的重点有两个,一个是定时器实现计算间隔时间和两个间隔时间相加的过程,另一个是对魔法方法“__str__”和“__repr__”的理解和讨论。

           作为一个新手,写博文的过程是自己学习过程中的总结,方便与大家交流和自我回顾,这便是我写博文的初衷。今天的源码是一个视频教程上的案例,而我的原创就是基于源码的总结与收获。源码如下:

import time as t#这里相当一个重命名,为了以后调用方便,time就干脆命名为tclass MyTimer:    def __init__(self):        self.unit = ['年','月','天','小时','分钟','秒']        self.prompt = '未开始计时'        self.lasted = []        self.begin = 0        self.end = 0    def __str__(self):        return self.prompt    __repr__ = __str__ #没有括号的应该,报错很明显如果后面有括号,那么肯定得具有形参    def start(self):        self.begin = t.localtime()        self.prompt = "请先停止再进行新的开始"        print("计时开始!")    def stop(self):        if not self.begin:            #self.prompt = "请先开始调用start"            print("请先调用start开始计时!")        else:            self.end = t.localtime()            self._calc()            print("计时结束!")    def _calc(self):        self.lasted = []        self.prompt = "总共运行了"        for index in range(6):            self.lasted.append(self.end[index] - self.begin[index])            if self.lasted[index]:                self.prompt  += (str(self.lasted[index]) + self.unit[index])        self.begin = 0        self.end = 0    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
          总的来说代码的逻辑还是挺清楚的,一共加了两处注释。一处是导入库时的更名操作,另一处是将魔法方法的__str__赋给__repr__,这里__str__不能写成__str__(),因为写成这样就需要一个位置参数,为空则报错,而如果再写成__str__(self),则会报self没有定义的错误。我的理解是,既然魔法方法是可以由自己来定义,而这一句的目的很明显,是将__str__方法返回的字符串的地址赋给__repr__。当检测到某实例对象的字符串形式的属性时会调用__str__,而这句代码又将__str__赋给__repr__,故返回的字符串实际地址中存的内容。如果有了括号,那么可能以为着__str__方法又重新定义。

          如果看到了这篇博文,又有兴趣尝试一下,我的建议是可以将源码放在Python的IDIE中新建的文件里,然后逐步进行尝试运行和分析,之后我会把我在IDIE上分析的过程详细讨论一下(尽管我粘上来的源码是在Pycharm上写的,哈哈,Pycharm舒服一点~~)

         我先简单说一下定时器的逻辑。除过构造方法和返回字符串的方法之外,还有四个方法,分别是记录开始时间(start())、记录终止时间(stop())、记录开始时间与终止时间之间的时间间隔(_calc(),这里定义为了一个内部方法)和重写的相加两个间隔时间的魔法方法(__add__(self,other))。根据之前对localtime()方法的解释,该方法返回的是一个列表,start()和stop()两个方法各自记录一个时刻,由_calc()方法根据两个时刻的差得到一个间隔时间,__add__方法的实现过程与_calc()类似。这两个方法的for循环,就是为了将得到的时刻由年至秒逐个相减(或相加),然后在给结果强制转换为字符串类型,方便连接之后的返回。

         下面是在IDIE中运行的内容:

=================== RESTART: D:/MajorDocuments/IDIEdoc.py ===================
>>> t1 = MyTimer()
>>> t1
未开始计时
>>> t1.start()
计时开始!
>>> t1.stop()
计时结束!
>>> t1
总共运行了11秒
>>> t2 = MyTimer()
>>> t2
未开始计时
>>> t2.stop()
请先开始start!
>>> t2.start()
计时开始!
>>> t2.start()
计时开始!
>>> t2
请先停止再进行新的开始
>>> t2.stop()
计时结束!
>>> t2
总共运行了32秒
>>> t1 + t2
'一共运行了43秒'
>>>
        

         t1和t2是类MyTimer的两个实例对象,首先在输入t1,构造方法中因为prompt的内容和__str__和__repr__,会打印prompt的内容。在start()方法中,会改写prompt,若输入t1,会将改写的prompt的打印出来,由此这里起到了一个提醒运行了start()而没有运行stop()的情况。同样在stop()中的if语句中,即在没有运行start()的情况下,会输出一句提醒没有开始。这里注释了一个改写prompt的代码,因为这句改写是不会输出的,除非是在先输入了stop()之后再输入t1,而这并不再是提醒的意思了。

        在__add__和_calc中也用到了prompt改写(严格地讲,应该都是新建一个字符串类型的对象,让prompt这个对象引用指向它)。

        连续两次输入start(),也就是在第二次再更新一下定义的开始时间的时刻,所以之后的stop()是以最后输入的start()的时刻为准。

       输入有过一对start()和stop()之后,再输入stop(),也就是连续两次输入stop()之后,第二次输入的结果会是返回一个请调用start()的提醒,原因是在_calc中的最后将实例对象的begin和end都重置为0。

       

0 0