python 多态、多继承、函数重写、迭代器
用于类的函数 issubclass(cls,class_or_tuple)
判断一个类是否继承自其他的类,如果此类cls是class或tuole中的一个派生(子类)则返回True,否则返回False
封装 enclosure
封装的目的是让使用者尽可能少的引用实例变量(属性)进行操作
私有属性:python类中,以双下划线‘__’开头,不以双下划线结尾的标识符为私有成员,在类的外部无法直接访问。
1 class A: 2 def __init__(self): 3 self.__p1 = 100 #__p1为私有属性,在类的外部不可访问 4 5 def test(self): 6 print(self.__p1) # 可以访问 7 self.__m1() # A类的方法可以调用A类的私有方法 8 9 def __m1(self): 10 '''我是私有方法,只有我自己的类中的方法才能调用我哦''' 11 print("我是A类的__m1方法!") 12 13 a = A() # 创建对象 14 # print(a.__p1) # 在类外看不到__p1属性,访问失败! 15 a.test() 16 # a.__m1() # 出错.无法调用私有方法
多态 polymorphic
多态是指在继承\派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖版本方法的现象叫多态
1 class Shape: 2 def draw(self): 3 print("Shape.draw被调用") 4 5 class Point(Shape) 6 def draw(self): 7 print('正在画一个点') 8 9 class Circle(Point): 10 def draw(self): 11 print("正在画一个圆") 12 13 def my_draw(s): 14 s.draw() # 此处显示出多态中的动态 15 16 s1 = Circle() 17 s2 = Point() 18 my_draw(s1) # 调用Circle里的draw 正在画一个圆 19 my_draw(s2) # 调用Point里的draw 正在画一个点
多继承 multiple inheritance
多继承是指一个子类继承自两个或两个以上的基类
说明:一个子类可以同时继承自多个父类,父类中的方法可以同时被继承下来。如果两个父类中有同名的方法,而在子类中又没有覆盖此方法时,调用结果难以确定
1 class Car: 2 def run(self, speed): 3 print("汽车以", speed, '公里/小时的速度行驶') 4 5 class Plane: 6 def fly(self, height): 7 print("飞机以海拔", height, '的高度飞行') 8 9 class PlaneCar(Car, Plane): 10 '''PlaneCar同时继承自汽车类和飞机类''' 11 12 p1 = PlaneCar() 13 p1.fly(10000) 14 p1.run(300)
多继承的问题(缺陷):名字冲突问题,要谨慎使用多继承(会先使用第一个继承的基类)
1 class A: 2 def m(self): 3 print("A.m()被调用") 4 5 class B: 6 def m(self): 7 print('B.m()被调用') 8 9 class AB(A, B): 10 pass 11 12 ab = AB() 13 ab.m() # A.m()被调用
继承的MRO(Method Resolution Order)问题
类的__mro__属性用来记录继承方法的查找顺序
1 class A: 2 def m(self): 3 print("A.m") 4 class B(A): 5 def m(self): 6 print("B.m") 7 class C(A): 8 def m(self): 9 print("C.m") 10 class D(B, C): 11 '''d类继承自B,C''' 12 def m(self): 13 print("D.m") 14 d = D() 15 print(D.__mro__) 16 #(<class '__main__.D'>, 17 # <class '__main__.B'>, 18 # <class '__main__.C'>, 19 # <class '__main__.A'>, 20 # <class 'object'>) 21 d.m() # 调用方法的顺序如上所示
1 class A: 2 def m(self): 3 print("A.m") 4 class B(A): 5 def m(self): 6 print("B.m") 7 super().m() 8 class C(A): 9 def m(self): 10 print("C.m") 11 super().m() 12 class D(B, C): 13 '''d类继承自B,C''' 14 def m(self): 15 print("D.m") 16 super().m() 17 d = D() 18 d.m() # 调用方法的顺序是什么? 19 20 for x in D.__mro__: 21 print(x) 22 23 24 # D.m 25 # B.m 26 # C.m 27 # A.m 28 # <class '__main__.D'> 29 # <class '__main__.B'> 30 # <class '__main__.C'> 31 # <class '__main__.A'> 32 # <class 'object'>
函数重写
在自定义类内添加相应的方法,让自定义类创建的实例能像内建对象一样进行内建函数操作
对象转字符串函数:
repr(obj) 返回一个能代表此对象的表达式字符串,通常eval(repr(obj))==obj (这个字符串通常是给python解释执行器运行用的)
对象转字符串函数的重写方法
reper(obj)函数的重写方法: def__repr__(self):
return 能够表达self内容的字符串
str(obj)函数的重写方法: def__str__(self):
return 人能看懂的字符串
1 class MyNumber: 2 def __init__(self, value): 3 self.data = value 4 def __str__(self): 5 print("__str__被调用") 6 return "数字: %d" % self.data 7 def __repr__(self): 8 print("__repr__被调用") 9 return 'MyNumber(%d)' % self.data 10 n1 = MyNumber(100) 11 # print(str(n1)) # 调用 n1.__str__(self);__str__被调用;数字: 100 12 # print(repr(n1)) #__repr__被调用 MyNumber(100) 13 print(n1) # ;__str__被调用;数字: 100 14 # n2 = eval("MyNumber(100)") 15 # print(n2) #__str__被调用;数字: 100
说明:
1、str(obj)函数先调用obj.__str__()方法,调用此方法并返回字符串
2、如果obj没有__str__()方法,则调用obj.__repr__()方法返回的字符串
3、如果obj没有__repr__()方法,则调用object类的__repe__()实例方法显示<xxxx>格式的字符串
数值转换函数的重写
def __complex__(self) complex(obj) 函数调用
def __int__(self) int(obj) 函数调用
def __float__(self) float(obj) 函数调用
def __bool__(self) bool(obj) 函数调用
1 '''此示例示意自定义的类MyNumber能够转成为数值类型''' 2 class MyNumber: 3 def __init__(self, v): 4 self.data = v 5 def __repr__(self): 6 return "MyNumber(%d)" % self.data 7 def __int__(self): 8 '''此方法用于int(obj) 函数重载,必须返回整数 9 此方法通常用于制订自义定对象如何转为整数的规则 10 ''' 11 return 10000 12 13 n1 = MyNumber(100) 14 print(type(n1)) 15 # if n1 == 100: 16 # print("n1 == 100") 17 n = int(n1) 18 print(type(n)) 19 print(n)
1 <class '__main__.MyNumber'> 2 <class 'int'> 3 10000
内建函数的重写
__abs__ abs(obj)
__len__ len(obj)
__reversed__ reversed(obj)
__round__ round(obj)
1 # 自定义一个MyList类,与系统内建的类一样, 2 # 用来保存有先后顺序关系的数据 3 4 class MyList: 5 '''自定义列表类''' 6 def __init__(self, iterator=[]): 7 self.data = [x for x in iterator] 8 9 def __repr__(self): 10 return "MyList(%r)" % self.data 11 12 def __abs__(self): 13 # return MyList([abs(x) for x in self.data]) 14 # 上一句语句可以用如下生成表达式代替已防止过多占内存 15 return MyList((abs(x) for x in self.data)) 16 17 def __len__(self): 18 # return self.data.__len__() 19 return len(self.data) 20 21 myl = MyList([1, -2, 3, -4]) 22 print(myl) 23 print(abs(myl)) # MyList([1, +2, 3, +4]) 24 print("原来的列表是:", myl) 25 26 myl2 = MyList(range(10)) 27 print(myl2) 28 print('myl2的长度是:', len(myl2)) 29 print('myl的长度是: ', len(myl))
1 MyList([1, -2, 3, -4]) 2 MyList([1, 2, 3, 4]) 3 原来的列表是: MyList([1, -2, 3, -4]) 4 MyList([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 5 myl2的长度是: 10 6 myl的长度是: 4
布尔测试函数的重写
格式 def __bool__(self):
...
作用:
用于bool(obj) 函数取值
用于if语句真值表达式中
用于while语句真值表达式中
说明:
1. 优先调用__bool__方法取值
2. 如果不存在__bool__方激动 ,则用__len__()方法取值后判断是否为零值,如果不为零返回True,否则返回False
3. 如果再没有__len__方法,则直接返回True
1 class MyList: 2 '''自定义列表类''' 3 def __init__(self, iterator=[]): 4 self.data = [x for x in iterator] 5 6 def __repr__(self): 7 return "MyList(%r)" % self.data 8 9 def __bool__(self): 10 print("__bool__方法被调用!") 11 return False 12 13 # def __len__(self): 14 # print("__len__被调用") 15 # return len(self.data) 16 17 myl = MyList([1, -2, 3, -4]) 18 print(bool(myl)) # False 19 if myl: 20 print("myl 是真值") 21 else: 22 print("myl 是假值")
1 __bool__方法被调用! 2 False 3 __bool__方法被调用! 4 myl 是假值
迭代器(高级)
可以通过next(it) 函数取值的对象就是迭代器
迭代器协议:迭代器协议是指对象能够使用next函数获取下一项数据,在没有下一项数据时触发一个StopIterator来终止迭代的约定
实现方法:类内需要有 __next__(self) 方法来实现迭代器协议
语法形式:
class MyIterator
def __next__(self):
迭代器协议的实现
return 数据
可迭代对象是指能用iter(obj) 函数返回迭代器的对象(实例),可迭代对象内部一定要定义__iter__(self)方法来返回迭代器
可迭代对象的语法形式:
class MyIterable:
def __iter__(self):
语句块
return 迭代器
# 此示例示意可迭代对象和迭代器的定义及使用方式: class MyList: def __init__(self, iterator): '''自定义列表类的初始化方法,此方法创建一个data实例 变量来绑定一个用来存储数据的列表''' self.data = list(iterator) def __repr__(self): '''此方法了为打印此列表的数据''' return 'MyList(%r)' % self.data def __iter__(self): '''有此方法就是可迭代对象,但要求必须返回迭代器''' print("__iter__方法被调用!") return MyListIterator(self.data) class MyListIterator: '''此类用来创建一个迭代器对象,用此迭代器对象可以迭代访问 MyList类型的数据''' def __init__(self, iter_data): self.cur = 0 # 设置迭代器的初始值为0代表列表下标 # it_data 绑定要迭代的列表 self.it_data = iter_data def __next__(self): '''有此方法的对象才叫迭代器, 此方法一定要实现迭代器协议''' print("__next__方法被调用!") # 如果self.cur已经超出了列表的索引范围就报迭代结束 if self.cur >= len(self.it_data): raise StopIteration # 否则尚未迭代完成,需要返回数据 r = self.it_data[self.cur] # 拿到要送回去的数 self.cur += 1 # 将当前值向后移动一个单位 return r myl = MyList([2, 3, 5, 7]) print(myl) for x in myl: print(x) # 此处可以这样做吗? # it = iter(myl) # x = next(it) # print(x) # x = next(it) # print(x) # x = next(it) # print(x)
1 MyList([2, 3, 5, 7]) 2 __iter__方法被调用! 3 __next__方法被调用! 4 2 5 __next__方法被调用! 6 3 7 __next__方法被调用! 8 5 9 __next__方法被调用! 10 7 11 __next__方法被调用!