Python-Task11 魔法方法
学习内容
小甲鱼python教程
魔法方法是小甲鱼老师提出来的一个名字,所谓python魔法方法,就是python天生拥有的一些方法,他们的名字被双下划线包围,在定义的类中,重载这些方法,这个方法就会在特殊的情况下被python所调用。魔法方法是面向对象的python的一切。
构造与析构
__init__(self[, ...])
该方法在一个实例被创建的时候自动被调用。可以在初始化的时候给实例挂上一些属性。
init方法返回None
__new__(cls[, ...])
该方法是对象实例化的时候第一个调用的方法。第一个参数是这个类,其他参数传给init方法。
new方法用于决定是否用该类的init方法。实际上,new可以调用其他类的init函数,或者直接返回其他类的实例。
class Capstr(str):
def __new__(cls,string):
string=string.upper()
return str.__new__(cls,string)
__del__(self)
析构器。当所有指向对象的引用全部被del之后,该方法会被自动启用
算数运算
可以自定义算数运算
算数运算符 | |
---|---|
__add__(self, other) | 定义加法的行为:+ |
__sub__(self, other) | 定义减法的行为:- |
__mul__(self, other) | 定义乘法的行为:* |
__truediv__(self, other) | 定义真除法的行为:/ |
__floordiv__(self, other) | 定义整数除法的行为:// |
__mod__(self, other) | 定义取模算法的行为:% |
__divmod__(self, other) | 定义当被 divmod() 调用时的行为 |
__pow__(self, other[, modulo]) | 定义当被 power() 调用或 ** 运算时的行为 |
__lshift__(self, other) | 定义按位左移位的行为:<< |
__rshift__(self, other) | 定义按位右移位的行为:>> |
__and__(self, other) | 定义按位与操作的行为:& |
__xor__(self, other) | 定义按位异或操作的行为:^ |
__or__(self, other) | 定义按位或操作的行为:| |
例如:下面的例子重构了加法,将+变为减法运算
>>> class new_int(int):
... def __add__(self,other):
... return int.__sub__(self,other)
...
>>> a=new_int(3)
>>> b=new_int(6)
>>> a+b
-3
反运算符:当左操作数不支持相应的操作时被调用
>>> class new_int(int):
... def __radd__(self,other):
... return int.__sub__(self,other) #注意一下顺序,在实际运算中,self是右对象,other是左对象
...
>>> a=new_int(5)
>>> 2+a
3
增量运算符:a=a+b => a+=b
一元操作符/二元操作符:分别有一个或两个操作对象的运算符。
计时器小练习
基本要求如下:
- 定制一个计时器的类。
start
和stop
方法代表启动计时和停止计时。- 假设计时器对象
t1
,print(t1)
和直接调用t1
均显示结果。 - 当计时器未启动或已经停止计时时,调用
stop
方法会给予温馨的提示。 - 两个计时器对象可以进行相加:
t1+t2
。 - 只能使用提供的有限资源完成。
import time
class Mytime():
def __init__(self):
self.unit=['年','月','日','时','分','秒']
self.start_time=0
self.prompt='还没开始计时'
self.end_time=0
print('时钟已创建')
def __str__(self):
return self.prompt
__repr__ = __str__
def __add__(self,other):
prompt='总共运行了'
res=[]
for i in list(range(6)):
res.append(self.result[i]+other.result[i])
if res[i]!=0:
prompt+=str(res[i])+self.unit[i]
return prompt
def start(self):
self.start_time=time.localtime()
self.start_time=self.start_time[0:6]
print("计时开始(使用stop()停止计时)")
def stop(self):
self.result=[]
if self.start_time==0:
print("你还没有开始计时")
else:
self.end_time=time.localtime()
self.prompt = "总运行了"
for i in list(range(6)):
self.result.append(self.end_time[i]-self.start_time[i])
if self.result[i]!=0:
self.prompt+=str(self.result[i])+self.unit[i]
print(self.prompt)
self.start_time=0
self.end_time=0
运行结果
>>> t1=Mytime()
时钟已创建
>>> t2=Mytime()
时钟已创建
>>> t1
还没开始计时
>>> t1.start()
计时开始(使用stop()停止计时)
>>> t1.stop()
总运行了8秒
>>> t2.start()
计时开始(使用stop()停止计时)
>>> t2.stop()
总运行了6秒
>>> t1+t2
'总共运行了14秒'
这个小程序还有一些小问题,可能会产生负数时间。我想到的两种解决方法,1.将时间转换为秒2.进行进位转换(相对复杂)
time模块详解:
https://fishc.com.cn/forum.php?mod=viewthread&tid=51326&extra=page%3D1%26filter%3Dtypeid%26typeid%3D403
属性访问
有关属性 | |
---|---|
getattr(self, name) | 定义当用户试图获取一个不存在的属性时的行为 |
getattribute(self, name) | 定义当该类的属性被访问时的行为 |
setattr(self, name, value) | 定义当一个属性被设置时的行为 |
delattr(self, name) | 定义当一个属性被删除时的行为 |
dir(self) | 定义当 dir() 被调用时的行为 |
get(self, instance, owner) | 定义当描述符的值被取得时的行为 |
set(self, instance, value) | 定义当描述符的值被改变时的行为 |
delete(self, instance) | 定义当描述符的值被删除时的行为 |
注意setattr和setattribution重构时的陷阱,容易陷入无限循环:
class Rec:
def __init__(self,width=0,height=0):
self.width=width
self.height=height
def __setattr__(self,name,value):
if name=='square':
self.width=value
self.height=value
else:
super().__setattr__(name,value) #调用基类方法来解决死循环
#self.__dict__[name]=value #或者使用字典的方式解决死循环
def getArea(self):
return self.width*self.height