上篇文章讲到覆盖的解决方法:如果我们向调用父类的同名方法:
1.用类名调用
2.super()函数,super无参调用方法只能在函数里面使用
一、issubclass函数 issubcalss(cls,class_or_tuple)
作用:
判断一个类是否继承者其他的类,如果此类cls 是class或者tuple中的一个派生类,返回True
示例:
class A:
pass
class B(A):
pass
class C(B):
pass
class D(B):
pass
print(issubclass(B,A))
print(issubclass(C,B))
print(issubclass(D,C))
#C是否是元组中的多个类中的某个类的派生类
print(issubclass(C,(int,str)))
执行结果:
True
True
False
False
二、封装 enclosure
封装是指隐藏类的实现细节,让使用者不关心这些细节
封装的目的是让使用者通过尽可能少的使用实例变量名(_ 属性 _)去操作对象
私有属性和方法
python类中以双’__'开头,不以双下划线结尾的标识符为私有成员
私有成员只能被方法调用,不能在子类或其他地方使用
私有成员:
私有属性
私有方法
实例:私有属性
class A:
def __init__(self):
self.__p1 = 100 #这里创建了一个私有的属性
def test(self): #但是我们可以在类的方法中进行操作,如test
print(self.__p1) #可以访问
a = A()
print(a.__p1) #这里出错不能访问,只能在类中进行访问修改
执行结果:
AttributeError: 'A' object has no attribute '__p1'
a.test() #通过类来访问这个私有变量,只能通过类的实现者封装的函数来访问,这样更安全
执行结果:
100
示例:私有方法
class A:
def __init__(self):
self.__p1 = 100 #这里创建了一个私有的属性
def test(self): #但是我们可以在类的方法中进行操作,如test
print(self.__p1) #可以访问
self.__f() #可以通过类调用类中私有方法
def __f(self):
print("A类的私有方法被调用")
a = A()
#a.__f() #类外不能调用,如果要调用也是需要通过类
a.test()
执行结果:
100
A类的私有方法被调用
三、多态: polymorphic
多态是指在有继承/派生关系的类中,调用基类对象的方法,实际能调用子类的覆盖方法的现象称为多态。
多态说明:
多态调用方法与对象相关,不与类相关
python的全部对象只有运行时的状态(动态):运行时才知道调用哪个方法
没有c++/java里的编译时状态(静态):编译时就知道调用哪个方法
示例:演示多态,解释见代码注释
class shape:
def draw(self):
pass
class point(shape):
def draw(self):
print("画一个点点")
class circle(point):
def draw(self):
print("画一个圈圈")
#多态在这里体现
def my_draw(s): #s的类型是什么在运行时才知道,根据类型再去决定调用什么
s.draw() #调用哪个方法?在运行时动态的决定调用的方法
#draw方法同名 相互覆盖
s1 = circle()
s2 =point()
my_draw(s1)
my_draw(s2)
执行结果:
画一个圈圈
画一个点点
四、面向对象的编程语言的特征
封装:1.用类封装 2.私有变量和方法
继承:基类和派生类
多态:主要是动态的多态(运行时的多态)
不同的对象,调用相同的方法,做着不同的事,其实就是多态
常见的面向对象语言:
C++/JAVA/Python/Swift/C#
五、多继承
多继承是指一个子类继承两个或者两个以上的基类
语法:
class 类名 (超类1,超类2....)
语句块
(仅限于c++和python中有多继承)
示例:多继承的一个例子
class car:
def run(self,speed):
print("以",speed,"km/h的速度行驶")
class plane:
def fly(self,height):
print("以海拔",height,"米的高度飞行")
class planecar(car,plane):#飞行汽车类,继承自两个类
pass
p = planecar()
p.fly(100)
p.run(99)
执行结果:
以海拔 100 米的高度飞行
以 99 km/h的速度行驶
多继承的问题:
标识符(名字空间)冲突问题
示例:
#小李写的A类
class A:
def m(self):
print("A.m()被调用")
#小张写的B类
class B():
def m(self):
print("B.m()被调用")
#小王感觉A和B写的不错 自己能用上
class AB(B,A): #先继承B后继承A,所以先在B中找方法
pass
# class AB(A,B): # 先继承A后继承B,所以先在A中找方法
# pass
ab = AB()
ab.m() #调用的是谁? 这样出现了不确定性,看你先继承谁,这不是我们想看到的
执行结果:
B
多继承的MRO问题:
即就是方法的搜索路径选择的问题,优先使用的多个基类的哪个同名方法,python3中以广度优先为搜索路径,python2中以深度优先
#这是派生类搜索路径的顺序,保存在__mro__属性中
for x in AB.__mro__:
print(x)
执行结果:
<class '__main__.AB'>
<class '__main__.B'>
<class '__main__.A'>
<class 'object'>
六、函数重写 overerite
在自定义的类中,通过添加特定的方法,让自定义的类生成的对象能像内建函数一样进行内建函数操作
对象转字符串函数重写:
repr( obj ):返回一个能代表此对象的字符串,通常: eval(repr(obj)) ==obj
str (obj) 通过给定的对象返回一个字符串(这个字符串是给人阅读的)
也就是说:
repr(obj)返回的字符串是给python用的
str(obj)返回的字符串是给人看的
重写方法:
repr(obj)函数的重写方法 def repr(self)
str(obj)函数的重写方法 def__str__(self)
当对象没有__str__方法时,则返回__repr__(self)的值