洗礼灵魂,修炼python(40)--面向对象编程(10)—定制魔法方法+time模块
定制魔法方法
1.什么是定制魔法方法
首先定制是什么意思呢?其实就是自定义了,根据我们想要的要求来自定义。而在python中,其实那些所谓的内置函数,内置方法,内置属性之类的其实也是自定义出来的,不过是龟数开发python时已经给出了,已经自带了基本能想到的功能都带有了,换句话就是已经给我们事先定义好了,要用的话,直接拿来就用就是,不需要我们自己再去定义。定制魔法方法就是自定义魔法方法了。但是必须遵循定制魔法方法的一些规则
2.怎么定制
说到定制魔法方法,那么魔法方法是哪里有的?类啊,要想定制魔法方法,那么必须得和类结合一起才行的
看一个简单的例子:
里面的__str__就是我们自己定制的魔法方法
看下还有哪些属性和方法呢?
我这里使用的是python3,前面说过了,因为在python3定义类时,即使不加object,python3也会默认给你把object基类加上,上面那些方法大部分都是继承object类的方法的。
不过这里要提一个魔法方法,前面忘了提了——__dict__
这个魔法方法是干什么的呢?是用于查看实例对象的属性的,格式:
对象名.__dict__#字典属性,与python内置的dir()函数功能有点类似
例:python3下
python2下:
但是如果是查看实例化的对象是空的
再看例子:
而使用__repr__魔法方法则不用print就可以直接返回
3.例子
场景:百米赛跑的运动会上,设置一个计时器,能准确无误的计时每个运动员跑完一百米后所用的时间,场上有5个赛道,有5个运动员同时比赛。只有一场比赛,用时较短者胜。
例子先放一边,既然需要计时器,那么首先这里得说个知识点——时间
在python中,通常三种方式来表示时间:
- struct_time元组
- 时间戳
- 格式化的时间字符串
一、struct_time元组
1.什么事struct_time元组:
这个元组很特殊,单独成类,但其实本质上是一个元组
2.怎么生成struct_time元组:使用time模块的localtime方法
这个元组共有九个元素,虽然都是使用=来连接,但它既不是字典也不是集合,就是哦这么特殊。
每个元素依次的含义:
索引(Index) | 属性(Attribute) | 值(Values) |
---|---|---|
0 | tm_year(年) | 比如2017 |
1 | tm_mon(月) | 1 - 12 |
2 | tm_mday(日) | 1 - 31 |
3 | tm_hour(时) | 0 - 23 |
4 | tm_min(分) | 0 - 59 |
5 | tm_sec(秒) | 0 - 61 |
6 | tm_wday(weekday) | 0 - 6(0表示周日) |
7 | tm_yday(一年中的第几天) | 1 - 366 |
8 | tm_isdst(是否是夏令时) | 默认为-1 |
最长用的就是前6个,后面三个基本不怎么用
二、时间戳(注意是戳,不是截取的截)
1.什么是时间戳
时间戳(timestamp),一个能表示一份数据在某个特定时间之前已经存在的、 完整的、 可验证的数据,通常是一个字符序列,唯一地标识某一刻的时间。是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。通俗的讲, 时间戳是一份能够表示一份数据在一个特定时间点已经存在的完整的可验证的数据。 它的提出主要是为用户提供一份电子证据, 以证明用户的某些数据的产生时间。 在实际应用上, 它可以使用在包括电子商务、 金融活动的各个方面, 尤其可以用来支撑公开密钥基础设施的 “不可否认” 服务(来自百度百科解释)
2.时间戳怎么生成:用time模块的time方法
3.时间戳与时间之间的转换:
1)时间转换为时间戳:
- 使用time模块的strptime方法将时间转为struct_time元组
- 使用time模块的mktime方法将struct_time元组转为时间戳
2)时间戳转为时间:
- 使用time模块的localtime方法将时间戳转为struct_time元组
- 使用time模块的strftime方法将struct_time元组转为时间
其实你有没有发现,时间戳和时间之间相互转换的中途都会使用struct_time元组作为中转站,就像字符编码里的unicode一样
三、格式化的时间字符串
时间也是字符串,作为一个特殊的时间字符串
格式化成新的格式的时间字符串
这里的【"%Y-%m-%d %H:%M:%S"】和【"%Y-%m-%d-%H-%M-%S"】里的%Y,%m,%d,%H,%M,%S都是定死了的,不能更改,就像%s代表字符串,%f代表浮点型数一样
符号 |
含义 |
%a |
本地(locale)简化星期名称 |
%A |
本地完整星期名称 |
%b |
本地简化月份名称 |
%B |
本地完整月份名称 |
%c |
本地相应的日期和时间表示 |
%d |
一个月中的第几天(01 - 31) |
%H |
一天中的第几个小时(24小时制,00 - 23) |
%I |
第几个小时(12小时制,01 - 12) |
%j |
一年中的第几天(001 - 366) |
%m |
月份(01 - 12) |
%M |
分钟数(00 - 59) |
%p |
本地am或者pm的相应符 |
%S |
秒(01 - 61) |
%U |
一年中的星期数。(00 - 53星期天是一个星期的开始。)第一个星期天之前的所有天数都放在第0周。 |
%w |
一个星期中的第几天(0 - 6,0是星期天) |
%W |
和%U基本相同,不同的是%W以星期一为一个星期的开始。 |
%x |
本地相应日期 |
%X |
本地相应时间 |
%y |
去掉世纪的年份(00 - 99) |
%Y |
完整的年份 |
%Z |
时区的名字(如果不存在为空字符) |
%% |
‘%'字符 |
注意:
- “%p”只有与“%I”配合使用才有效果
- 文档中强调确实是0 - 61,而不是59,闰年秒占两秒
- 当使用strptime()函数时,只有当在这年中的周数和天数被确定的时候%U才会被计算
有了以上的解析,相信你已经对time模块了解得差不多了。
那么接着看例子,我们要解决那个计时器,就必须得具备上面的知识点,才能解决这个问题
import time as t class Timer(): def __init__(self): self.unit=['年','月','天','小时','分钟','秒','星期','一年中的天数','夏令时'] self.string='未开始比赛' self.last=[] self.begin=0 self.end=0 def __str__(self): return self.string __repr__=__str__ #这个方法前面说过,当调用方法时,会自动打印方法下的字符串 def start(self): self.begin=t.localtime() self.string='请务必保证事先已调用stop()归零' print('计时开始...') def stop(self): if not self.begin: print('请务必保证事先已调用start()开始计时') else: self.end=t.localtime() self.result() print('计时结束') def result(self): self.last=[] self.string='运动员总共用时' for index in range(9): self.last.append(self.end[index]-self.begin[index]) if self.last[index]: self.string += (str(self.last[index])+self.unit[index]) self.begin=0 self.end=0 def __add__(self,other): string='运动员总共用时' result=[] for i in range(9): result.append(self.last[i]+other.last[i]) print(result) if result[i]: string += (str(result[i])+self.unit[i]) #print(string) return string
代码是用于计算一个运动员比赛用时的,开始测试结果:
由于在实际开发中都会先测试再真正投入使用。这里没有问题,进行真正使用
#-*- coding:utf-8 -*- import time class Timer(): def __init__(self): self.unit=['年','月','天','小时','分钟','秒'] self.string='未开始比赛' self.last=[] self.begin=0 self.end=0 def __str__(self): return self.string __repr__=__str__ #这个方法前面说过,当调用方法时,会自动打印方法下的字符串 def start(self): self.begin=time.localtime() self.string='请务必保证事先已调用stop()归零' #print('计时开始...') def stop(self): if not self.begin: print('请务必保证事先已调用start()开始计时') else: self.end=time.localtime() self.result() #print('计时结束') def result(self): self.last=[] self.string='总共用时' for i in range(6): self.last.append(self.end[i]-self.begin[i]) if self.last[i]: self.string += (str(self.last[i])+self.unit[i]) self.begin=0 self.end=0 if __name__== '__main__': print('准备比赛,运动员上场') print('1号运动员就位') player1=Timer() print('2号运动员就位') player2=Timer() print('3号运动员就位') player3=Timer() print('4号运动员就位') player4=Timer() print('5号运动员就位') player5=Timer() print('各就各位,准备。。。。开始!') player1.start() player2.start() player3.start() player4.start() player5.start() time.sleep(9) #这是time模块里的方法,作为暂时停顿,单位是秒 player1.stop() time.sleep(0.5) player2.stop() time.sleep(0.5) player3.stop() time.sleep(0.5) player4.stop() time.sleep(0.5) player5.stop() print('所有运动员已经跑完百米,比赛结束') print('1号运动员的成绩为:',player1) print('2号运动员的成绩为:',player2) print('3号运动员的成绩为:',player3) print('4号运动员的成绩为:',player4) print('5号运动员的成绩为:',player5)
结果:
你会想,等会儿,本篇博文主题不是定制魔法方法吗?这里用到了?
是的用到了,不过用的少,只有一个__repr__ = __str__ ,慢慢来,在面向对象章节了还有很多知识点。
那么你可能会想,怎么5个运动员的开始起跑和到达终点都是手动控制的,可以同时进行吗?可以的,后面说到多线程和异步的时候就会说到,这里先暂时忽略本问题吧
PS:我的博文也会尽量把知识面覆盖完,有时候为了把相关知识全部拿出来,所以思维都是一个网状式的,可能突然想起什么去解析这里然后同时又忘记那里就没有拿出来解析,这个也请见谅,我只是一个自学编程的无名人士,不是大佬,也没有多少写博文的经验,有时候为了说明一个知识点,自创一个例子来举例也可以能举的不是很好(比如上面的计时器例子,我想了很久才想到和自定义魔法方法沾边的,能力有限,没办法),那些例子也不知道你们能不能看懂,总之,以后继续努力