一:魔法方法
1.__str__()
>>> class A(): def __str__(self): return "小甲鱼是帅哥" >>> a=A() >>> print(a) 小甲鱼是帅哥
2.__repr__()
>>> class B(): def __repr__(self): return "小甲鱼是帅哥" >>> b=B() >>> b 小甲鱼是帅哥
3.简单定制:
基本要求:
定制一个计时器类
start和stop方法代表启动计时和停止计时
假设计时器对象t1,print(t1)和直接调用t1均显示结果
当计时器未启动或已经停止计时,调用stop方法会给予温馨提示
两个计时器对象可以进行相加:t1+t2
只能使用提供有限资源完成
import time as t class MyTime(): def __init__(self): #进行变量和函数的初始化 self.unit=['年','月','天','时','分','秒'] #时间单位 self.prompt='未开始计时' #提示语句 self.lasted=[] #持续时间存储的列表 self.begin=0 #开始时间初始化 self.end=0 #结束时间初始化 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停止计时' 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 print(self.prompt) #停止计时 def stop(self): if not self.begin: print('提示:请先调用start()进行计时') else: self.end=t.localtime() self._calc() print('计时结束!') t1=MyTime() t2=MyTime() t1.start() t.sleep(45) t1.stop() t2.start() t.sleep(15) t2.stop() print(t1+t2)
使用time模块的localtime方法获取时间。time.localtime返回struct_time的时间格式:
包括:tm_year 年
月 tm_mon
日 tm_mday
时 tm_hour
分 tm_min
秒tm_sec
weekday:0-6 0表示周日 tm_wday
一年中的第几天1-366 tm_yday
是否是夏令时 tm_isdst
4.属性访问
用__getattr__()魔法方法
>>> c=C() >>> c.x 'X_man' >>> getattr(c,'x','没有这个属性') 'X_man' >>> getattr(c,'y','没有这个属性') '没有这个属性'
用property
>>> class C: def __init_(self,size=10): self.size=size def getSize(self): return self.size def setSize(self,value): self.size=value def delSize(self): del self.size x=property(getSize,setSize,delSize) >>> c=C() >>> c.x=1 >>> c.x 1 >>> del c.x >>> c.size Traceback (most recent call last): File "<pyshell#42>", line 1, in <module> c.size AttributeError: 'C' object has no attribute 'size'
5.几个魔法方法:
__getattr__(self,name)
定义当用户试图获取一个不存在的属性时的行为
__getattribute__(self,name)
定义当该类的属性被访问时的行为
__setattr__(self,name,value)
定义当一个属性被设置时的行为
__delattr__(self,name)
定义当一个属性被删除时的行为
>>> class C: def __getattribute__(self,name): print('getttribute') return super().__getattribute__(name) def __getattr__(self,name): print('getattr') def __setattr__(self,name,value): print('setattr') super().__setattr__(name,value) def __delattr__(self,name): print('delattr') super().__delattr__(name) >>> c=C() >>> c.x getttribute getattr >>> c.x=1 setattr >>> c.x getttribute 1 >>> del c.x delattr
练习:
写一个矩形类,默认有宽和高两个属性。如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,此时宽和高都等于边长。
>>> class Rectangle: def __init__(self,width=0,height=0): self.width=width self.height=height #当这两个属性被定义时,调用__setattr__() def __setattr__(self,name,value):#重写魔法方法 if name=='square': self.width=value self.height=value else: super().__setattr__(name,value) #调用基类的__setattr__方法 def getArea(self): return self.width*self.height >>> r=Rectangle() >>> r1=Rectangle(4,5) >>> r1.getArea() 20 >>> r1.square=10 >>> r1.height 10 >>> r1.width 10 >>> r1.getArea() 100
二:描述符
描述符(Property的原理):描述符就是将某种特殊类型的类(含有以下三个魔方的一个或多个)的实例指派给另一个类的属性。
__get__(self,instance,owner)
用于访问属性,它返回属性的值
__set__(self,instance,value)
将在属性分配操作中调用,不返回任何内容
__delete__(self,inatance)
控制删除操作,不返回任何内容
>>> class MyDecriptor: def __get__(self,instance,owner): print('getting...',self,instance,owner) def __set__(self,instance,value): print('setting',self,instance,value) def __delete__(self,instance): print('deleting',self,instance) >>> class Test: x=MyDecriptor() >>> test=Test() >>> test.x getting... <__main__.MyDecriptor object at 0x00357C50> <__main__.Test object at 0x00357FB0> <class '__main__.Test'> >>> test <__main__.Test object at 0x00357FB0> >>> Test <class '__main__.Test'> >>> test.x='X_man' setting <__main__.MyDecriptor object at 0x00357C50> <__main__.Test object at 0x00357FB0> X_man >>> del test.x deleting <__main__.MyDecriptor object at 0x00357C50> <__main__.Test object at 0x00357FB0>
① self: MyDecriptor的实例对象,其实就是Test的属性x
② instance: Test的实例对象,其实就是test
③ owner: 即谁拥有这些东西,当然是 Test 这个类,它是最高统治者,其他的一些都是包含在它的内部或者由它生出来的
可以利用这个重写Property
2.练习:
先定义一个温度类,然后定义两个描述符用于描述摄氏度和华氏度两个属性。要求两个属性会自动进行转换,也就是说你可以给摄氏度这个属性赋值,然后打印的华氏度属性是自动转换后的结果。
>>> class Celsius: def __init__(self,value=26.0): self.value=float(value) def __get__(self,instance,owner): return self.value def __set__(self,instance,value): self.value=float(value) >>> class Fahrenheit: def __get_(self,instance,owner): return instance.cel*1.8+32 def __set__(self,instance,value): instance.cel=(float(value)-32)/1.8 >>> class Temperature: cel=Celsius() fah=Fahrenheit() >>> temp=Temperature() >>> temp.cle Traceback (most recent call last): File "<pyshell#125>", line 1, in <module> temp.cle AttributeError: 'Temperature' object has no attribute 'cle' >>> temp.cel 26.0 >>> temp.fah=100 >>> temp.cel 37.77777777777778
三:练习
定制序列:
编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数
>>> class CountList: def __init__(self,*args): self.values=[x for x in args] self.count={}.fromkeys(range(len(self.values)),0) def __len__(self): return len(self.value) def __getitem__(self,key): self.count[key]+=1 return self.values[key] >>> c1=CountList(1,3,5,7,9) >>> c2=CountList(2,4,6,8,10) >>> c1[1] 3 >>> c2[1] 4 >>> c1[1]+c2[1] 7 >>> c1.count {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
四:迭代器
两个BIF:iter() next()
>>> string='fishc' >>> it=iter(string) >>> next(it) 'f' >>> next(it) 'i' >>> next(it) 's' >>> next(it) 'h' >>> next(it) 'c' >>> next(it) Traceback (most recent call last): File "<pyshell#160>", line 1, in <module> next(it) StopIteration
>>> string='fishc' >>> it=iter(string) >>> while True: try: each=next(it) except StopIteration: break print(each) f i s h c
魔法方法:__iter__() __next__()
>>> class Fibs: def __init__(self): self.a=0 self.b=1 def __iter__(self): return self def __next__(self): self.a,self.b=self.b,self.a+self.b return self.a >>> fibs=Fibs() >>> for each in fibs: if each<30: print(each) else: break 1 1 2 3 5 8 13 21
五:生成器
生成器:生成器就像一个特殊的迭代器
>>> def myGen(): print('生成器被执行') yield(1) yield(2) >>> myG=myGen() >>> next(myG) 生成器被执行 1 >>> next(myG) 2 >>> next(myG) Traceback (most recent call last): File "<pyshell#203>", line 1, in <module> next(myG) StopIteration
生成器,斐波拉契数列
>>> def libs(): a=0 b=1 while True: a,b=b,a+b yield a >>> for each in libs(): if each >100: break print(each,end=' ') 1 1 2 3 5 8 13 21 34 55 89