面向对象编程 封装 继承 多态(三大特征)(第三篇)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/dongzixian/article/details/90383662

封装

封装是面向对象编程的三大特征之一。
封装有两方面的含义:
1.将数据(属性)和行为(方法)包装到类对象中。方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度。
2.在类对象的内部通过访问控制把某些属性和方法隐藏起来,不允许在类对象的外部直接访问,而是在类对象的内部对外提供公开的接口方法以访问隐藏的信息。这样,就对隐藏的信息进行了保护。
class Student(object):
    def __init__(self):
        self.__a = 90
    def get_a(self):
        return self.__a
    def set_a(self,a):
        if 0 <= a <= 100:
            self.__a = a
        else:
            raise ValueError("成绩必须在0~100之间")
s = Student()
s.get_a()
>90
s = Student()
s.set_a(88)
print(s.get_a())
>88
s.set_a(123)
>---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-14-1c4873c0a02d> in <module>()
----> 1 s.set_a(123)

<ipython-input-11-fc87181632fe> in set_a(self, a)
      8             self.__a = a
      9         else:
---> 10             raise ValueError("成绩必须在0~100之间")

ValueError: 成绩必须在0~100之间

继承

当几个类对象中有共同的属性和方法时,就可以把这些属性和方法抽象并提取到一个基类中,每个类对象特有的属性和方法还是在本类对象中定义,这样,只需要让每个类对象都继承这个基类,就可以访问基类中的属性和方法了。继承基类的每个类对象被称为派生类。基类也被称为父类或超类,派生类也被称为子类。
python中的所有类对象都继承自一个统一的基类:object。这就是为什么我们在定义类对象时要在类名后面添加(object)。
除了封装,继承也是面向对象编程的三大特征之一。继承是实现代码复用的重要手段。
class Animal(object):
    def eat(self):
        print("吃饭")
    def drink(self):
        print("喝水")
class Bird(Animal):
    def fly(self):
        print("飞")
class Dog(Animal):
    def swim(self):
        print("游泳")
dog = Dog()
dog.eat()
>吃饭
bird = Bird()
bird.drink()
>喝水
bird.fly()
>飞
  • 单继承:子类只有一个直接父类时称为单继承
  • 多继承:子类有多个直接父类时称为多继承
  • 子类会继承所有父类(包括所有直接父类和所有间接父类)的所有属性和方法

重写

  • 如果子类对继承自父类的某个属性或方法不满意,可以在子类中对其进行重写从而提供自定义的实现
  • 重写的方式为:在子类中定义与父类中同名的属性或方法(包括装饰器)
  • 子类重写父类的属性或方法后,通过子类或其实例对象只能访问子类中重写后的属性或方法,而无法再访问父类中被重写的属性
class ParentClass(object):
    a = "a(父)"
    def __init__(self):
        print("__init__()被调用了(父)")
    @classmethod
    def cm(cls):
        print("cm()被调用了(父)")
class ChildClass(ParentClass):
    a = "a(子)"
    def __init__(self):
        print("__init__()被调用了(子)")
    @classmethod
    def cm(cls):
        print("cm()被调用了(子)")
cc = ChildClass()
print(ChildClass.a)
print(cc.a)
ChildClass.cm()
cc.cm()
>__init__()被调用了(子)
a(子)
a(子)
cm()被调用了(子)
cm()被调用了(子)
父类中被重写的名为xxx的方法,在子类重写后的方法中可以通过super().xxx()进行调用 要分清实例方法和类方法

MRO(方法解析顺序method resolution order)

对于一颗类继承树,可以调用最底层类对象最底层类对象的方法mro()或访问最底层类对象的特殊属性__mro__,获得这棵树的MRO
class A(object):
    def f(self):
        print("A.f")
class B(A):
    def f(self):
        print("B.f")
class C(A):
    def f(self):
        print("c.f")
class D(B,C):
    def f(self):
        print("D.f")
print(D.__mro__)
>(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
print(D.mro())
>[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
如果想调用指定父类中被重写的方法,可以给super()传入两个实参:super(a_type,obj) 其中,第一个实参是个类对象,第二个实参是个实例对象,这样,被指定的父类是:obj所对应类对象的MRO中,a_type后面那个类对象
class A(object):
    def f(self):
        print("A.f")
class B(A):
    def f(self):
        print("B.f")
class C(A):
    def f(self):
        print("C.f")
class D(B,C):
    def f(self):
        super().f()
d = D()
d.f()
>B.f
class A(object):
    def f(self):
        print("A.f")
class B(A):
    pass
class C(A):
    def f(self):
        print("C.f")
class D(B,C):
    def f(self):
        super().f()
d = D()
d.f()
>C.f
class A(object):
    def f(self):
        print("A.f")
class B(A):
    pass
class C(A):
    pass
class D(B,C):
    def f(self):
        super().f()
d = D()
d.f()
>A.f

多态(在不考虑对象类型的情况下使用对象)

除了封装和继承,多态也是面向对象编程的三大特征之一。
简单地说,多态就是“具有多种形态“,它指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态地决定调用哪个对象中的方法
如果子类中不存在指定名称的方法,回到父类中去查找,如果在父类中找到了,则调用父类中的方法。

猜你喜欢

转载自blog.csdn.net/dongzixian/article/details/90383662