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


    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()方法,这就是互称为鸭子类型。

  • 相关阅读:
    第1组 团队Git现场编程实战
    第二次结对编程作业
    团队项目-需求分析报告
    团队项目-选题报告
    第一次结对编程作业
    第一次个人编程作业
    第一次博客作业
    2019 SDN上机第二次作业
    2019 SDN上机第一次作业
    软件工程第五次作业
  • 原文地址:https://www.cnblogs.com/wangyueping/p/11094635.html
Copyright © 2020-2023  润新知