Python面向对象中的继承、多态和封装

一、面向对象的三大特性

  1. 封装:把很多数据封装到⼀个对象中,把固定功能的代码封装到⼀个代码块, 函数,对象, 打包成模块。 这都属于封装思想。
  2. 继承:⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容。 说⽩了, ⼉⼦可以随便⽤爹的东⻄。
  3. 多态: 同⼀个对象, 多种形态。在Python中处处是多态,因为在Python中一个变量可以是多种形态。

二、封装

封装,顾名思义,就是将某些东西给封装起来,以后想要使用的时候再去调用。

所以,在使用面向对象的封装特性时需要:① 将内容封装到某处 ② 调用时从某处取出来

封装分为两部分:

  1. 广义上的封装:实例化一个对象,给对象空间封装一些属性。
  2. 狭义上的封装:私有制。私有成员:私有静态属性,私有方法,私有对象属性。

我们先看广义上的封装:

  1. 将内容封装到某处

    class MyClass:
    def __init__(self, name, age):
    self.name = name
    self.age = age # 在实例化对象时,会自动执行__init__方法,将对象空间传递给self这个位置参数
    obj = MyClass("oldniu", 20)
    # 将"oldniu" 和 20 分别封装到obj(self)的name和age属性中
  2. 从某处调用封装的内容

    调用被封装的内容时,有两种方式:① 通过对象直接调用 ② 通过self间接调用

    1. 通过对象直接调用

      class MyClass:
      def __init__(self, name, age):
      self.name = name
      self.age = age obj = MyClass("oldniu", 20)
      print(obj.name) # 通过obj对象直接调用里面的name属性
      print(obj.age) # 通过obj对象直接调用里面的age属性
    2. 通过self间接调用

      class MyClass:
      def __init__(self, name, age):
      self.name = name
      self.age = age def func(self):
      print(self.name) # 使用self间接调用obj对象中的name属性
      print(self.age) # 使用self间接调用obj对象中的age属性 obj = MyClass("oldniu", 20)
      obj.func() # 对象执行方法时Python会默认将obj传给参数self

    综上所述,对于面向对象广义上的封装来说,其实就是使用初始化方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。

    我们再看狭义上的封装

    1. 私有静态属性

      class MyClass:
      __gender = "男" # 私有静态属性 def __init__(self, name, age):
      self.name = name
      self.age = age def get_gender(self):
      return self.__gender # 在类的内部可以访问私有静态属性 # print(MyClass.__gender) # 类名不能直接访问私有静态属性 obj = MyClass("oldniu", 20)
      # print(obj.__gneder) # 对象不能访问私有静态属性 print(obj.get_gender()) # 男

      对于私有静态字段来说,只能在本类中内部访问,类的外部,子类均不可访问。

      tips:其实在类的外部可以通过使用_MyClass__gender访问私有静态属性,但是一般我们不会去使用。

    2. 私有方法

      class MyClass:
      
          def __init__(self, name, age):
      self.name = name
      self.age = age def __func(self):
      print("666666") def func(self):
      self.__func() 类内部访问静态方法 obj = MyClass("dogfa", 20)
      obj.func()
      # 私有方法和私有静态字段一样,只能在本类中内部访问,类的外部和子类均不课访问。

    三、继承

    什么是继承?⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容就是继承。

    1. 继承的优点

      1. 提高代码的复用性
      2. 提高代码的维护性
      3. 使类与类之间发生关联
    2. 继承的分类
      1. 单继承
      2. 多继承

    我们先来看单继承

    1. 类名,对象执行父类方法

      # 定义一个Animal父类
      class Animal:
      type_name = "动物类" def __init__(self, name):
      self.name = name def eat(self):
      print("吃吃吃...") # 继承于Animal类
      class Dog(Animal):
      pass # 类名调用父类的属性和方法
      print(Dog.type_name)
      Dog.eat(111) # 对象调用父类的属性和方法
      dog = Dog("二哈") # 调用父类的__init__方法实例化对象
      print(dog.name)
      print(dog.type_name)
      dog.eat()
      print(dog.__dict__)
    2. 执行顺序

      1. 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
      2. 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。
    3. 同时执行类及父类方法

      方法一:

      如果想执行父类的func方法,这个方法并且子类中夜用,那么就在子类的方法中写上:

      父类.func(对象,其他参数)

      class Animal:
      type_name = "动物类" def __init__(self, name, age, gender):
      self.name = name
      self.age = age
      self.gender = gender def eat(self):
      print("吃吃吃...") class Bird(Animal):
      def __init__(self, name, age, gender, wing):
      Animal.__init__(self, name, age, gender) # 执行了父类的__init__方法进行初始化
      self.wing = wing # 给对象封装wing属性 obj = Bird("鹦鹉", 3, "雌", "翅膀")
      print(obj.__dict__)
      # {'name': '鹦鹉', 'age': 3, 'gender': '雌', 'wing': '翅膀'}

      方法二:

      利用super,super().func(参数)

      class Animal:
      type_name = "动物类" def __init__(self, name, age, gender):
      self.name = name
      self.age = age
      self.gender = gender def eat(self):
      print("吃吃吃...") class Bird(Animal):
      def __init__(self, name, age, gender, wing):
      super().__init__(name, age, gender) # 使用super会自动将self传给父类
      self.wing = wing # 给对象封装wing属性 obj = Bird("鹦鹉", 3, "雌", "翅膀")
      print(obj.__dict__)
      # {'name': '鹦鹉', 'age': 3, 'gender': '雌', 'wing': '翅膀'}

    再来看看多继承

    在多继承中要补充一点,在这里要注意类的种类。类可以分为经典类新式类

    新式类:继承object类的类称为新式类。在Python3中默认都是继承object类,所以默认所有类都是新式类。

    经典类:不继承object类的类称为经典类。在Python2中默认使用经典类,当然也可以自己手动继承object类来达到变成经典类的目的。

    1. 经典类的多继承

      在Python的继承体系中, 我们可以把类与类继承关系化成⼀个树形结构的图。

      class A:
      pass
      class B(A):
      pass
      class C(A):
      pass
      class D(B, C):
      pass
      class E:
      pass
      class F(D, E):
      pass
      class G(F, D):
      pass
      class H:
      pass
      class Foo(H, G):
      pass

      对付这种mro画图就可以:

      继承关系图已经有了,那如何进⾏查找呢? 记住⼀个原则, 在经典类中采⽤的是深度优先遍历⽅案。 什么是深度优先,就是⼀条路走到头, 然后再回来, 继续找下⼀个。

      类的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C

    2. 新式类的继承

      1. mro序列

        MRO是一个有序列表L,在类被创建时就计算出来。

        通用计算公式为:

        mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
        (其中Child继承自Base1, Base2)

        如果继承至一个基类:class B(A)

        这时B的mro序列为

        mro( B ) = mro( B(A) )
        = [B] + merge( mro(A) + [A] )
        = [B] + merge( [A] + [A] )
        = [B,A]

        如果继承至多个基类:class B(A1, A2, A3 …)

        这时B的mro序列

        mro(B) = mro( B(A1, A2, A3 …) )
        = [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
        = ...

        计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。

      2. 表头和表位

        表头:

          列表的第一个元素

        表尾:

          列表中表头以外的元素集合(可以为空)

        示例

          列表:[A, B, C]

          表头是A,表尾是B和C

      3. 列表之间的+操作

        +操作:

        [A] + [B] = [A, B]

        (以下的计算中默认省略)

        ---------------------

        merge操作示例:

        如计算merge( [E,O], [C,E,F,O], [C] )
        有三个列表 : ① ② ③ 1 merge不为空,取出第一个列表列表①的表头E,进行判断
        各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
        2 取出列表②的表头C,进行判断
        C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
        merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
        3 进行下一次新的merge操作 ......
        ---------------------

        计算mro(A)方式:

        mro(A) = mro( A(B,C) )
        
        原式= [A] + merge( mro(B),mro(C),[B,C] )
        
          mro(B) = mro( B(D,E) )
        = [B] + merge( mro(D), mro(E), [D,E] ) # 多继承
        = [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O]
        = [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D
        = [B,D,E] + merge([O] , [O])
        = [B,D,E,O] mro(C) = mro( C(E,F) )
        = [C] + merge( mro(E), mro(F), [E,F] )
        = [C] + merge( [E,O] , [F,O] , [E,F] )
        = [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除
        = [C,E,F] + merge([O] , [O])
        = [C,E,F,O] 原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
        = [A,B] + merge( [D,E,O], [C,E,F,O], [C])
        = [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E
        = [A,B,D,C] + merge([E,O], [E,F,O])
        = [A,B,D,C,E] + merge([O], [F,O]) # 跳过O
        = [A,B,D,C,E,F] + merge([O], [O])
        = [A,B,D,C,E,F,O]
        ---------------------

三、多态

多态:同一个对象,多种形态。

由于Python是弱类型语言, 在定义变量和传参的时候可以是任意形态的值,所以Python默认支持多态。

鸭子类型:你看起来像鸭子,那就是鸭子。

对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。比如list、tuple、str都有index()方法,这就是互称为鸭子类型。

Python面向对象中的继承、多态和封装的更多相关文章

  1. Python面向对象,析构继承多态

    析构: def __del__(self): print("del..run...") r1 = Role("xx") del r1 结果打印del..run. ...

  2. 47、Python面向对象中的继承有什么特点?

    继承的优点: 1.建造系统中的类,避免重复操作. 2.新类经常是基于已经存在的类,这样就可以提升代码的复用程度. 继承的特点: 1.在继承中基类的构造(__init__()方法)不会被自动调用,它需要 ...

  3. Python面向对象三要素-继承(Inheritance)

    Python面向对象三要素-继承(Inheritance) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.继承概述 1>.基本概念 前面我们学习了Python的面向对象三 ...

  4. JavaScript面向对象中的继承

    1.1继承的基本概念 使用一个子类,继承另一个父类,那么子类可以自动拥有父类中的所有属性和方法,这个过程叫做继承. >>>继承的两方,发生在两个类之间. 实现继承的三种方式: 扩展O ...

  5. Python面向对象中的“私有化”

    Python面向对象中的“私有化” Python并不直接支持私有方式,而要靠程序员自己把握在外部进行特性修改的时机. 为了让方法或者特性变为私有(从外部无法访问),只要在它的名字前面加上双下划线即可. ...

  6. python面向对象中的封装、继承、多态

    封装 可以简单的理解为隐藏一切可以隐藏的实现细节,只向外界提供简单的编程接口.我们在类中定义的方法其实就是把数据和数据的操作封装起来了,在我们创建了对象之后,只需要给对象发送一个消息(调用方法)就可以 ...

  7. Python面向对象初始(三大特征,多态,继承,封装)

    Python面向对象的初始 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优点是:极大的降低了写程序的 ...

  8. python oop常用术语 继承 多态 封装

    面向对象优点 1.通过封装明确了内外 2.通过继承+多态在语言层面支持了归一化设计 抽象/实现 抽象指对现实世界问题和实体的本质表现,行为和特征建模,建立一个相关的子集,可以用于 绘程序结构,从而实现 ...

  9. python 面向对象专题(四):封装、多态、鸭子类型、类的约束、super

    https://www.cnblogs.com/liubing8/p/11321099.html 目录 Python面向对象04 /封装.多态.鸭子类型.类的约束.super 1. 封装 2. 多态 ...

随机推荐

  1. tomcat发布web项目

    转:https://www.cnblogs.com/skyblue-li/p/7888951.html Tomcat是一种Web服务器,我们自己做好了一个Web项目,就可以通过Tomcat来发布.服务 ...

  2. 重读APUE(5)-文件权限

    文件,目录,权限 1. 用名称打开任一个类型的文件时,对该名字中包含的每一个目录,包括它可能隐含的当前工作目录都应该具有执行权限:这就是目录执行权限通常被称为搜索位的原因: 例如:为了打开文件/usr ...

  3. Sublime Markdown预览插件安装流程

    使用方法 在sublime中已编辑好的markdown使用快捷键 Alt+M 即可在浏览器预览效果. 需要安装的插件 Markdown Editting:主要用来做 Markdown 编辑时的语法高亮 ...

  4. 【Linux】安装 node.js

    1.在 linux 上安装 node.js 有几种方式,这里 教的是最简单的一种,因为其他都比较坑. 2.先去 node.js 官网 获取到已经编译好的安装包的地址, 3.使用 wget 去下载上面获 ...

  5. 淘宝rem适配方案

    /*px 转化换 rem ,转化是 10 .比如:你的设计图为750,那么就 750 / 75 = 10 rem.设计图中你量尺寸都要除 75 就是 rem值.再比如量的设计图按钮宽度 66px,那么 ...

  6. 周志华-机器学习西瓜书-第三章习题3.5 LDA

    本文为周志华机器学习西瓜书第三章课后习题3.5答案,编程实现线性判别分析LDA,数据集为书本第89页的数据 首先介绍LDA算法流程: LDA的一个手工计算数学实例: 课后习题的代码: # coding ...

  7. 5G 与 MEC 边缘计算

    目录 文章目录 目录 前言 参考文献 通信网络 核心网演进之路 早古时期 2G 网络架构 3G 网络架构 4G 网络架构 5G 5G 网络的需求 5G 网络架构的设计原则 5G 网络的逻辑架构 5G ...

  8. 动手生成 Delphi xe DBTreeview

    tProductType表结构如下 object FDConnection1: TFDConnection    Params.Strings = (      'Database=ClothingT ...

  9. 【leetcode】506. Relative Ranks

    problem 506. Relative Ranks solution1:使用优先队列: 掌握priority_queue 和 pair的使用: class Solution { public: v ...

  10. 【世界之大,我用Python】Ubuntu 自动删除自带软件

    起因 Ubuntu是用来做开发程序的系统,如果存在大量的"垃圾"软件就不好了吧,不仅影响系统性能而且还会经常报错,所以每次安装完系统都会清理一次系统. 操作 我清理系统一般都是直接 ...