一、基本需求

  • 定制一个计时器的类
  • start和stop方法表示启动计时和停止计时
  • 假设计时器对象t1,print(t1)和直接调用t1均显示结果
  • 当计时器未启动或已停止计时,调用stop方法会给予温馨提示
  • 两个计时器对象可以进行相加或相减(获取两次计时的和或者差)

二、需求分析

1.定制一个计时器的类

class MyTimer:
    pass

2.start和stop方法表示启动计时和停止计时

Python 程序能用很多方式处理日期和时间,转换日期格式是一个常见的功能。Python 提供了time 模块可以用于格式化日期和时间。其中time模块中的localtime()方法可以获取当前时间并以元组的形式返回,Python用一个元组装起来的9组数字处理时间格式如下:

import time as t

class MyTimer:
    def start(self):
        self.start = t.localtime()
        print("开始计时...")

    def stop(self):
        self.stop = t.localtime()
        print("计时结束...")

3.假设计时器对象t1,print(t1)和直接调用t1均显示结果

首先肯定是实现计算start和stop之间的差值,因此定义一个函数用于计算,有上述可知localtime()返回的是一个元组,因此可以通过索引的方式依次计算差值

实现直接调用t1显示结果,当我们直接调用t1或者打印对象时会得到对象的内存地址

<__main__.MyTimer object at 0x000001F853F7A1D0>

这里就需要请出python魔法方法__str____repr__,这两个方法都是用于显示的,要说区别就只能理解为__str__面向用户,__repr__面向开发者,因此我们可以重写__str__方法用于返回时间差值

import time as t

class MyTimer:
    def __init__(self):
        self.start = 0
        self.stop = 0
        self.lasted = []

    def __str__(self):
        return str(self.lasted)

    #开始计时
    def start(self):
        self.start = t.localtime()
        print("开始计时...")

    #结束计时
    def stop(self):
        self.stop = t.localtime()
        self.__cal()
        print("计时结束...")

    #计算差值
    def __cal(self):
        for index in range(6):
            self.lasted.append(self.stop[index] - self.start[index])

if __name__ == '__main__':
    t1 = MyTimer()
    t1.start()
    t.sleep(1)    #程序暂停1s
    t1.stop()
    print(t1)

运行的时候会报TypeError(一个大坑)…先考虑几秒

Traceback (most recent call last):
  File "E:/Pycharm/Project/Note/MyTimer.py", line 30, in <module>
    t1.start()
TypeError: 'int' object is not callable

说我的t1.start()有错误并提示int对象不能被调用,这是什么原因呢???是因为类的属性名与方法名一样了,当我们调用方法时会被属性覆盖,因此会显示int对象不能被调用,只需要将属性名修改即可[start->begin;stop->end]

开始计时...
计时结束...
[0, 0, 0, 0, 0, 1]

4.当计时器未启动或已停止计时,调用stop方法会给予温馨提示

考虑到构造函数时begin和end都为0,因此可以在stop()方法里面添加判断begin是否为0即可,并做了一些简单的处理让上面的结果更加易读

import time as t

class MyTimer:
    def __init__(self):
        self.begin = 0
        self.end = 0
        self.lasted = []
        self.unit = ['年','月','天','小时','分钟','秒']
        self.prompt = "未开始计时"

    def __str__(self):
        return self.prompt

    #开始计时
    def start(self):
        self.begin = t.localtime()
        self.prompt = "请先调用stop()停止结束"  #防止开始后不结束,直接调用t1
        print("开始计时...")

    #结束计时
    def stop(self):
        if not self.begin:  #非0即真
            print("请先调用start()开始计时")
        else:
            self.end = t.localtime()
            self.__cal()
            print("计时结束...")

    #计算差值
    def __cal(self):    
        self.lasted = []    #清一下,就是想清
        self.prompt = "总共运行了"
        for index in range(6):
            self.lasted.append(self.end[index] - self.begin[index])
            if self.lasted[index]:  #非0即真,筛选lasted中的0元素并添加单位
                self.prompt += (str(self.lasted[index])+self.unit[index])   
        #归零
            self.begin = 0  
            self.end = 0

if __name__ == '__main__':
    t1 = MyTimer()
    t1.start()
    t.sleep(1)
    t1.stop()
    print(t1)

我发现针对这个需求的调试Pycharm真的没有IDLE好用

5.两个计时器对象可以进行相加或相减

python中万物皆对象,即使是简单的1+1也是对象之间的操作,会调用int对象中的__add__()方法,因此我们可以重新定义__add__()方法来实现类似C++中的运算符的重载

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

三、IDLE演示

最终代码如下

import time as t

class MyTimer:
    def __init__(self):
        self.begin = 0
        self.end = 0
        self.lasted = []
        self.unit = ['年','月','天','小时','分钟','秒']
        self.prompt = "未开始计时"


    def __str__(self):
        return self.prompt


    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()停止结束"  #防止开始后不结束,直接调用t1
        print("开始计时...")

    #结束计时
    def stop(self):     
        if not self.begin:  #非0即真
            print("请先调用start()开始计时")
        else:
            self.end = t.localtime()
            self.__cal()
            print("计时结束...")

    #计算差值
    def __cal(self):    
        self.lasted = []    #清一下,就是想清
        self.prompt = "总共运行了"
        for index in range(6):
            self.lasted.append(self.end[index] - self.begin[index])
            if self.lasted[index]:  #非0即真,筛选lasted中的0元素并添加单位
                self.prompt += (str(self.lasted[index])+self.unit[index])
        #归零
        self.begin = 0
        self.end = 0

演示结果如下:

为什么会有负数呢???比如

begin: 2020年2月16日20时10分00秒
end: 2021年1月17日21时9分50秒

根据程序定义的方法结果应该是

1年-1月1天1小时-1分钟50秒

因此我们需要将其转换为正常人看得懂的结果

11月1天59分钟50秒

小学减法算式告诉我们个位不够向十位借一,因此可以针对self.lasted后序遍历,若为负数则向前借一直到self.lasted列表元素全部为非负数即可[注:一年365天,一月30天不考虑闰年,月大月小等因素]

import time as t

class MyTimer:
    def __init__(self):
        self.begin = 0
        self.end = 0
        self.lasted = []
        self.unit = ['年','月','天','小时','分钟','秒']
        self.prompt = "未开始计时"


    def __str__(self):
        return self.prompt

    def __repr__(self):
        return self.prompt


    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()停止结束"  #防止开始后不结束,直接调用t1
        print("开始计时...")

    #结束计时
    def stop(self):     
        if not self.begin:  #非0即真
            print("请先调用start()开始计时")
        else:
            self.end = t.localtime()
            self.__cal()
            self.__sortOut()
            print("计时结束...")

    #计算差值
    def __cal(self):
        self.lasted = []    #清一下,就是想清
        for index in range(6):
            self.lasted.append(self.end[index] - self.begin[index])
        #归零
        self.begin = 0
        self.end = 0

    def __sortOut(self):
        while True:
            if self.lasted[5] < 0:
                self.lasted[4] -= 1
                self.lasted[5] += 60

            if self.lasted[4] < 0:
                self.lasted[3] -= 1
                self.lasted[4] += 60

            if self.lasted[3] < 0:
                self.lasted[2] -= 1
                self.lasted[3] += 24

            if self.lasted[2] < 0:
                self.lasted[1] -= 1
                self.lasted[2] += 30

            if self.lasted[1] < 0:
                self.lasted[0] -= 1
                self.lasted[1] += 365

            if self.lasted[0] < 0:
                print('检查数据')

            if self.lasted[0] >= 0 and self.lasted[1] >= 0 and self.lasted[2] >= 0 and self.lasted[3] >= 0 \
                    and self.lasted[4] >= 0 and self.lasted[5] >= 0:
                break

        self.prompt = "总共运行了"
        for index in range(6):
            if self.lasted[index]: #非0即真
                self.prompt += (str(self.lasted[index]) + self.unit[index])

  • 整理自《零基础入门学习Python》(小甲鱼)

只喜欢学习