1.构造和析造
魔法方法就是被双下划线包围的方法
__init__()
方法
__init__
方法默认没有参数,返回值为none。类实例化对象需有明确的初始化步骤要重写函数
>>> class Rectangle: def __init__(self,x,y): self.x = x self.y = y def getPeri(self): return (self.x+self.y)*2 def getArea(self): return self.x * self.y >>> rect = Rectangle(3,4) >>> rect.getPeri() 14 >>> rect.getArea() 12 >>> #init返回值一定是None >>> class A: def __init__(self): return "A" >>> a = A() Traceback (most recent call last): File "", line 1, in a = A() TypeError: __init__() should return None, not 'str'
__new__()
方法
__new__()
方法在实例化对象时返回一个实例对象,参数是cls,是第一个被调用的方法
>>> class CapStr(str): def __new__(cls,string): string = string.upper() return str.__new__(cls,string) >>> a = CapStr("I love FishC.com") >>> a 'I LOVE FISHC.COM'
__del__()
方法
__del__()
方法在对象将要被销毁时被调用
>>> class C: def __init__(self): print("我是init方法,我被调用了") def __del__(self): print("我是del方法,我被调用了") >>> c1 = C() 我是init方法,我被调用了 >>> c2 = c1 >>> c3 = c2 >>> del c3 >>> del c2 >>> del c1 我是del方法,我被调用了
对象生成后,所有对它的引用都被del之后,才会启动垃圾回收机制
2.算数运算
运算符 | 对应的魔法方法 | 中文注释 |
---|---|---|
+ | __ add__(self, other) | 加法 |
- | __ sub__(self, other) | 减法 |
* | __ mul__(self, other) | 乘法 |
/ | __ truediv__(self, other) | 真除法 |
// | __ floordiv__(self, other) | 整数除法 |
% | __ mod__(self, other) | 取余除法 |
divmod(a, b) | __ divmod__(self, other) | 把除数和余数运算结果结合 |
** | __ pow__(self, other[,modulo]) | self的other次方再对modulo取余 |
<< | __ lshift__(self, other) | 按位左移 |
>> | __ rshift__(self, other) | 按位右移 |
& | __ and__(self, other) | 按位与操作 |
^ | __ xor__(self, other) | 按位异或操作(同为0,异为1) |
丨 | __ or__(self, other) | 按位或操作(有1则1) |
反运算的魔方方法
>>> class Nint(int): def __radd__(self,other): return int.__sub__(self,other) >>> a = Nint(5) >>> b = Nint(3) >>> a + b 8 >>> 1 + b 2 >>> #此处执行了3-1,self是3,other是1
3. 简单定制(计时器)
import time as t class 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 __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 stop(self): if not self.begin: 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 print(self.prompt) >>> t1 = MyTimer() >>> t2 = MyTimer() >>> t1.start() 计时开始 >>> t2.start() 计时开始 >>> t1.stop() 总共运行了1分21秒 计时结束 >>> t2.stop() 总共运行了15秒 计时结束 >>> t1 总共运行了1分21秒 >>> t2 总共运行了15秒 >>> t1+t2 '总共运行了1分36秒'
利用perf_counter()和process_time()
import time as t class MyTimer: def __init__(self): self.prompt = "未开始计时" self.lasted = 0.0 self.begin = 0 self.end = 0 self.default_timer = t.perf_counter def __str__(self): return self.prompt __repr__ = __str__ def __add__(self,other): result = self.lasted + other.lasted prompt = "总共运行了%0.2f秒" % result return prompt def start(self): self.begin = self.default_timer() self.prompt = "提示:请先调用stop()停止计时" print("计时开始!") def stop(self): if not self.begin: print("提示:请先调用start()开始计时") else: self.end = self.default_timer() self._calc() print("计时结束") def _calc(self): self.lasted = self.end - self.begin self.prompt = "总共运行了%0.2f秒" % self.lasted print(self.prompt) self.begin = 0 self.end = 0 def set_timer(self,timer): if timer == 'process_time': self.default_timer = t.process_time elif timer == 'perf_counter': self.default_timer = t.perf_counter else: print("输入无效") t1 = MyTimer() t1.set_timer('perf_counter') t1.start() t.sleep(5.2) t1.stop() t2 = MyTimer() t2.set_timer('perf_counter') t2.start() t.sleep(5.2) t2.stop() print(t1 + t2) >>> 计时开始! 总共运行了5.23秒 计时结束 计时开始! 总共运行了5.21秒 计时结束 总共运行了10.44秒 >>>
4.属性访问
魔法方法 | 含义 |
---|---|
__ getattr__(self, name) | 定义当用户试图获取一个不存在的属性时的行为 |
__ getattribute__(self, name) | 定义当该类的属性被访问时的行为 |
__ setattr__(self, name, value) | 定义当一个属性被设置时的行为 |
__ delattr__(self, value) | 定义当一个属性被删除时的行为 |
避免属性魔法方法的死循环:
使用super()调用基类、给特殊属性__dict__
赋值
class Rectangle: 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 >>> r1 = Rectangle(4,5) >>> r1.getArea() 20 >>> r1.square = 10 >>> r1.getArea() 100 >>>
5. 描述符
将某种特殊类型的类的实例指派给另一个类的属性
__get__(self,instance,owner) |
访问属性,返回属性的值 |
---|---|
__set__(self,instance,value) |
在属性分配中调用,不返回任何内容 |
__delete__(self,instance) |
控制删除操作,不返回任何值 |
>>> class Mydecript: 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 = Mydescript() Traceback (most recent call last): File "", line 1, in class Test: File "", line 2, in Test x = Mydescript() NameError: name 'Mydescript' is not defined >>> class Test: x = Mydecript() #Mydecript是x的描述类 >>> test = Test() >>> test.x getting... <__main__.Mydecript object at 0x030EAFB0> <__main__.Test object at 0x03108050> >>> test.x = "X-man" setting... <__main__.Mydecript object at 0x030EAFB0> <__main__.Test object at 0x03108050> X-man >>> del test.x deleting... <__main__.Mydecript object at 0x030EAFB0> <__main__.Test object at 0x03108050>
例题:温度的转换
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.cel 26.0 >>> temp.cel = 30 >>> temp.fah 86.0 >>> temp.fah = 100 >>> temp.cel 37.77777777777778 >>>
6.定制序列
例题:编写一个不可变的自定义列表,要求记录列表中每个元素被访问的次数
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.values) def __getitem__(self,key): self.count[key] += 1 return self.values[key] >>> c1 = CountList(1,3,5,7,9) >>> c1[1] 3 >>> c2 = CountList(2,4,6,8,10) >>> c2[1] 4 >>> c1[1]+c2[1] 7 >>> c1.count {0: 0, 1: 2, 2: 0, 3: 0, 4: 0} >>> c2[1] 4 >>> c2.count {0: 0, 1: 3, 2: 0, 3: 0, 4: 0} >>>
7.迭代器
迭代器是实现了__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 "", line 1, in next(it) StopIteration >>> string = "FishC" >>> it = iter(string) >>> while True: try: each = next(it) except StopIteration: break print(each) F i s h C >>> for each in string: print(each) F i s h C >>>
例题:使用迭代器实现斐波那契数列
>>> class Fibs: def __init__(self,n=10): self.a = 0 self.b = 1 self.n = n def __iter__(self): return self def __next__(self): self.a,self.b = self.b,self.a + self.b if self.a > self.n: raise StopIteration return self.a >>> fibs = Fibs() >>> for each in fibs: print(each) 1 1 2 3 5 8