python与面向对象(issubclass、封装、多态、多继承)4

上篇文章讲到覆盖的解决方法:如果我们向调用父类的同名方法:
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)的值

猜你喜欢

转载自blog.csdn.net/KingOfMyHeart/article/details/89174008