zoukankan      html  css  js  c++  java
  • 写给小白的Python之017:面向对象-封装、继承、多态

     

    1. 封装

    面向对象三大特性:封装、继承、多态

    封装(Encapsulation)这是定义类的 准则,单个类。根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中。

    封装的意义:

    1.将属性和方法放到一起做为一个整体,然后通过实例化对象来处理;

    2.隐藏内部实现细节,只需要和对象及其属性和方法交互就可以了;

    3.对类的属性和方法增加 访问权限控制。

     

    2. 继承

    继承:这是设计类的 技巧,父与子。

    • 主要体现是实现代码的 重用,相同的代码不需要重复的编写;
    • 子类可以在父类功能上进行重写,扩展类的功能。

    在面向对象编程中,当我们已经创建了一个类,而又想再创建一个与之相似的类,比如添加几个方法,或者修改原来的方法,这时我们不必从头开始,可以从原来的类派生出一个新的类, 我们把原来的类称为父类或基类,而派生出的类称为子类或派生类,子类继承了父类的所有数据和方法。

    从技术上说, OOP里继承最主要的用途是实现多态。对于多态而言,重要的是接口继承性,属性和行为是否存在继承性,这是不一定的。事实上, 大量工程实践表明,重度的行为继承会导致系统过度复杂和臃肿,反而会降低灵活性。因此现在比较提倡的是基于接口的轻度继承理念。这种模型里因为父类(接口类)完全没有代码,因此根本谈不上什么代码复用。

    2.1 单继承

    子类的定义如下:

    class 子类名(父类名):

        <statement-1>

        ...

        <statement-N>

    父类名 BaseClassName 对于子类来说必须是可见的。也可以继承在其他模块中定义的父类:

    class 子类名(模块名.父类名):

    对于子类的属性引用:首先会在当前的子类中搜索,如果没有找到,则会递归地去父类中寻找。

    从C++术语上讲,Python 类中所有的方法都是 vitual 的,所以子类可以覆写(override)父类的方法。在子类中一个覆写的方法可能需要调用父类的方法,可以通过以下方式:

    父类名.方法(self, arguments)

     

    2.2 多继承

    Python支持多继承,一个多继承的定义形如:

    class 子类名(父类名1, 父类名2, 父类名3):

    多个父类有同名属性和方法

    子类的魔法属性__mro__决定了属性和方法的查找顺序。如果多个父类中有同名的 属性和方法,则默认使用第一个父类的属性和方法(根据类的魔法属性mro的顺序来查找)

    子类重写父类的属性和方法

    子类和父类的方法名和属性名相同,则默认使用子类的,叫 子类重写父类的同名方法和属性。

    使用重写的目的:当子类发现父类的大部分功能都能满足需求,但是有一些功能不满足,则子类可以重写父类方法。

    2.3 调用父类方法

    重写之后,如果发现仍然需要父类方法,则可以强制调用父类方法。

    方法1. 指定执行父类的方法

    无论何时何地,self都表示是子类的对象。在调用父类方法时,通过传递self参数,来控制方法和属性的访问修改。通常用于多继承。

    • 父类名.父类方法(self, 参数列表)
    • 父类名().属性/方法   # 不推荐这样访问父类的实例属性,相当于创建了一个新的父类对象

    子类继承了多个父类,如果父类类名修改了,那么子类也要涉及多次修改。而且需要重复写多次调用,显得代码臃肿。

    方法2. super() 带参数版本

    只支持新式类,支持Python2和3。工作中使用这个。

    • super(子类名, self).父类方法(参数列表)

    # super(子类名, self).__init__() # 执行父类的 __init__方法

    # self.方法名()

    示例:

    class Animal:
    
        def __init__(self, age):  # 1.父类有时候需要接收一些参数
            self.age = age
    
    
    class Cat(Animal):
    
        def __init__(self, age):  # 3.一般情况下,父类需要的参数,子类也是动态来获取
            self.name = '伊丽莎白'
            super(Cat, self).__init__(age)  # 2.子类需要为父类传递实参
    
    
    cat = Cat(12)  # 4. 根据子类需求,传递对应的实参
    print(cat.age)  # 12

    方法3. super()的简化版

    只支持新式类,只支持Python3

    • super().父类方法(参数列表)  # 执行父类的 实例方法

    super().__init__()  # 执行父类的 __init__方法

    知识点:

    • 使用super() 可以逐一调用所有的父类方法,并且只执行一次。调用顺序遵循 mro 类属性的顺序。
    • 注意:如果继承了多个父类,且父类都有同名方法,则默认只执行第一个父类的(同名方法只执行一次,目前super()不支持执行多个父类的同名方法)
    • super() 在Python2.3之后才有的机制,用于通常单继承的多层继承。

    3. 多态

    多态是指对不同类型的变量进行相同的操作,它会根据对象(或类)类型的不同而表现出不同的行为。即 不同类的对象调用相同方法,产生不同的结果。

    多态(Polymorphism):

    • 不同的子类对象调用相同的父类方法,产生不同的 执行结果;父类能工作的地方,子类都能工作;
    • 多态以继承和重写父类方法为前提;
    • 多态是调用方法的技巧,不会影响到类的内部设计。

    多态的好处:

    在保证安全性的前提下,提高了方法调用的灵活性。

    多态的实现:

    1.定义一个父类

    2.定义多个子类,并重写父类的方法

    3.传递子类对象给调用者,不同子类对象能产生不同执行效果

    示例:

    class Dog(object):
        def work(self):  # 父类提供统一的方法,哪怕是空方法
            pass
    
    class ArmyDog(Dog):   # 继承 Dog
        def work(self):  # 子类重写方法,并且处理自己的行为
            print('追击敌人')
    
    class DrugDog(Dog):
        def work(self):
            print('追查毒品')
    
    class Person(object):
        def work_with_dog(self, dog):
            dog.work()    # 使用小狗可以根据对象的不同而产生不同的运行效果, 保障了代码的稳定性
     
    
    # 子类对象可以当作父类来使用
    dog = Dog()
    print(isinstance(dog, Dog))  # True
    
    ad = ArmyDog()
    print(isinstance(ad, Dog))  # True
    
    dd = DrugDog()
    print(isinstance(dd, Dog))  # True
    
    p = Person()
    p.work_with_dog(dog)
    p.work_with_dog(ad)  # 同一个方法,只要是 Dog 的子类就可以传递,提供了代码的灵活性
    p.work_with_dog(dd)  # 并且传递不同对象,最终 work_with_dog 产生了不同的执行效果
    
    # 最终效果
    # Person 类中只需要调用 Dog 对象 work() 方法,而不关心具体是 什么狗
    # work() 方法是在 Dog 父类中定义的,子类重写并处理不同方式的实现
    # 在程序执行时,传入不同的 Dog 对象作为实参,就会产生不同的执行效果

    多态总结:

    # 定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果。

    # 好处:调用灵活,有了多态,更容易编写出通用的代码,做出通用的编程,以适应需求的不断变化!

    鸭子类型:

    动态语言的“鸭子类型”(duck typeing),它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。即只要一个对象相似的属性和方法。

    动态语言的鸭子类型特点决定了继承不像静态语言那样是必须的。

    类型检查是毁掉多态的利器, 比如type、 isinstance以及isubclass函数,所以,一定要慎用这些类型检查函数。

  • 相关阅读:
    编译和安装在Windows上橡胶树 (Compiling and Installing Yate on Windows)
    Microsoft Sync Framework 2.1 可再发行程序包 Microsoft Sync Framework 1.0 SP1
    Kwickserver
    .net平台 基于 XMPP协议的即时消息服务端简单实现
    开源jabber(XMPP)架设内部即时通讯服务的解决方案
    www.mentalis.org/
    VM虚拟机ping不通局域网其他主机的解决办法
    VM Workstation的Unity Mode有什么用
    Office WORD EXCEL批量查找和替换技巧实例
    Visual Studio VS如何拷贝一个项目的窗体文件到另一个项目
  • 原文地址:https://www.cnblogs.com/salmond/p/9001257.html
Copyright © 2011-2022 走看看