魔法方法总是被双下划线包围,例如__init__
魔法方法是面向对象的python的一切
魔法方法总能够在适当的时候被自动调用
_init_(self[, …])
问题:在写类定义的时候有些写__init__方法,有些却没有,为什么?
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) print(rect.getPeri()) #周长 print(rect.getArea()) #面积
14 12
_new_(cls[, …])
upper()
class CapStr(str): def __new__(cls, string): string = string.upper() return str.__new__(cls, string) a = CapStr('Hu zhuzhu') print(a)
HU ZHUZHU
_del_(self)
错误表示: del x = x._del_()
class C: def __init__(self): print('我是__init__方法,我被调用了...') def __del__(self): print('我是__del__方法,我被调用了...') c1 = C() c2 = c1 c3 = c2 del c3 del c1
print(type(len)) print(type(dir)) print(type(int)) print(type(list)) class C: pass print(type(C)) print(type(int('123'))) print(type('123'))
<class 'builtin_function_or_method'> <class 'builtin_function_or_method'> <class 'type'> <class 'type'> <class 'type'> <class 'int'> <class 'str'>
class New_int(int): def __add__(self, other): return int.__sub__(self, other) def __sub__(self, other): return int.__add__(self, other) a = New_int(3) b = New_int(5) print(a+b) #int(a)-int(b) print(a-b)
-2 8
class Try_int(int): def __add__(self, other): return int(self) + int(other) def __sub__(self, other): return int(self) - int(other) a = Try_int(3) b = Try_int(5) print(a+b) print(a-b)
8 -2
class int(int): def __add__(self, other): return int.__sub__(self, other) #返回减法 a = int('5') b = int(3) print(a+b)
2
class Nint(int): def __radd__(self, other): return int.__sub__(self, other) a = Nint('5') print(a) b = Nint(3) print(a+b) print(1+b)
5 8 2
class Nint(int): def __radd__(self, other): return int.__sub__(other, self) a = Nint('5') print(3-a)
-2
定时器
class A(): def __str__(self): return '胡猪猪' a = A() print(a) class B(): def __repr__(self): return '胡大猪' b = B() print(b)
胡猪猪 胡大猪
import time as t #调用import, t = import 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): #前六个,0-5 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)
描述符
就是将某种特殊类型的类的实例指派给另一个类的属性。
_get_(self, instance, owner)
用于访问属性,它返回属性的值
_set_(self, instance, value)
将在属性分配器操作中调用,不返回任何内容
_delete_(self, instance)
控制删除操作,不返回任何内容
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 print(test) print(Test) test.x = 'X.man'
getting... <__main__.MyDecriptor object at 0x0000014D64D845C8> <__main__.Test object at 0x0000014D64D846C8> <class '__main__.Test'> <__main__.Test object at 0x0000014D64D846C8> #test <class '__main__.Test'> #Test setting... <__main__.MyDecriptor object at 0x0000014D64D845C8> <__main__.Test object at 0x0000014D64D846C8> X.man
class MyProperty: def __init__(self, fget=None, fset=None, fdel=None): self.fget = fget self.fset = fset self.fdel = fdel def __get__(self, instance, owner): #用于访问属性,它返回属性的值 return self.fget(instance) def __set__(self, instance, value): #将在属性分配器操作中调用,不返回任何内容 self.fset(instance, value) def __delete__(self, instance): #控制删除操作,不返回任何内容 self.fdel(instance) class C: def __init__(self): self._x = None #private def getX(self): return self._x def setX(self, value): self._x = value def delX(self): del self._x x = MyProperty(getX, setX, delX) c = C() c.x = 'X.man' #赋值 print(c.x) print(c._x)
X.man X.man
练习1:摄氏度华氏度转换
1、先定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性
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.cel = 30 print(temp.fah) temp.fah = 86 print(temp.cel)
86.0 30.0
协议
协议(Protocols)与其他编程语言中的接口很相似,它规定你哪些方法必须要定义。然而,在python中的协议就显得不那么正式。事实上,在python中,协议更像是一种指南。
容器类型的协议
1、如果定制的容器是不可变的,只需定义__len__()和__getitem__()方法。
2、如果定制的容器是可变的,除了__len__()和__getitem__()方法,还需定义__setitem__()和__delitem__()两个方法。
练习2
编写一个不可改变的自定义列表,要求记录列表中每个元素被访问的次数。
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) c2 = CountList(2,4,6,8,10) print(c1[1]) print(c2[1]) print(c1[1]+c2[1]) print(c1.count) print(c2.count)
3 4 7 {0: 0, 1: 2, 2: 0, 3: 0, 4: 0} {0: 0, 1: 2, 2: 0, 3: 0, 4: 0}
迭代
for i in 'FishC': print(i)
F i s h C
links = {'胡猪猪':'是猪',\ '胡大猪':'shizhu',\ '胡二猪':'是只猪',\ '胡三猪':'zhu'} for each in links: print('%s -> %s' % (each, links[each]))
胡猪猪 -> 是猪 胡大猪 -> shizhu 胡二猪 -> 是只猪 胡三猪 -> zhu
迭代器
iter()
next()
string = 'Fishc' it = iter(string) print(next(it)) print(next(it)) print(next(it)) print(next(it)) print(next(it))
F i s h c
string = 'Fishc' it = iter(string) while True: try: each = next(it) except StopIteration: break print(each) for each in string: print(each)
F i s h c 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 #self.a = self.b #self.b = self.a + self.b return self.a fibs = Fibs() for each in fibs: if each < 20: print(each) else: break #大于等于20跳出循环输出
1 1 2 3 5 8 13 #等于前两个数相加
版本二
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 #大于10生成错误输出 return self.a fibs = Fibs() for each in fibs: if each < 20: print(each) else: break
1 1 2 3 5 8
版本三
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(100) #这个不一样 for each in fibs: print(each) #没有了if-else
1 1 2 3 5 8 13 21 34 55 89