**类知识点2**

**在子类中调用父类的两种方法**

方式一 父类名.父类方法()

    class Vehicle:  # 定义交通工具类
        Country = 'China'

        def __init__(self, name, speed, load, power):
            self.name = name
            self.speed = speed
            self.load = load
            self.power = power
   
        def run(self):
            print('开动啦...')

    class Subway(Vehicle):  # 地铁类嵌入交通工具类
        def __init__(self, name, speed, load, power, line):
            Vehicle.__init__(self, name, speed, load, power)  # 父类名.父类方法
            self.line = line

    def run(self):
        print('地铁%s号线欢迎您' % self.line)
        Vehicle.run(self)

    line13 = Subway('中国地铁', '180m/s', '1000人/箱', '电', 13)  # 实例化类,创造出一个类
    line13.run()   # 类绑定方法
方法1中,使用了父类名.父类方法(),

     Vehicle.__init__(self, name, speed, load, power)
   
方法二 使用super()函数

    class Vehicle: #定义交通工具类
         Country='China'
         def __init__(self,name,speed,load,power):
             self.name=name
             self.speed=speed
             self.load=load
             self.power=power
   
         def run(self):
             print('开动啦...')

    class Subway(Vehicle): # 地铁
        def __init__(self,name,speed,load,power,line):
                #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
                super().__init__(name,speed,load,power)
                self.line=line
       
        def run(self):
            print('地铁%s号线欢迎您' %self.line)
            super(Subway,self).run()
    class Mobike(Vehicle):#摩拜单车
        pass

    line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
    line13.run()
               
方法2使用了super(),
  
    super().__init__(name,speed,load,power)

super()相当于实例本身,在python3中super()等同于super(Subway,self)  方式一不依赖于继承,方式二依赖继承,即便没有直接的继承关系,super仍然会按照mro继续往后找

   
  
    class A:
        def test(self)
            super().test()
       
    class B:
        def test(self):
            print('from B')
       
    class C(A,B):
        pass
    c=C()
    c.test() #打印结果:from B

在以上代码中,c=C(),表示实例化C类,创建c对象,c.test(),绑定test()方法属性到c对象,由于c无test方法属性,类C也没有,因此将从继承的A类里找,找到test(),因为test()方法属性里出现super().test(),super()的意义在于即使没有继承关系,仍然会按照mro线性顺序列表继续往后找对象基类。

**组合与重用性**

软件重用的重要方式除了继承之外还有另外一种方式,即:组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合

继承中,类与类之间的关系为什么是什么的关系,组合则是什么有什么的关系

    class Head: # 英雄头饰类
         def head(self):
             print('猪头')
   
    class Equip: #武器装备类
         def fire(self):
             print('release Fire skill')
    
    class Riven: #英雄Riven的类,一个英雄需要有装备,还可以装扮头像,因而需要组合Equip,Head类
         camp='Noxus'
         def __init__(self,nickname):
             self.nickname=nickname
             self.equip=Equip()
             self.head=[] #用Equip类产生一个装备,赋值给实例的equip属性
    
     r1=Riven('锐雯雯')
     r1.equip.fire()  # 可以使用组合的类产生的对象所持有的方法
     r1.head.apend(Head())
     r1.head[0].head()# 可以使用组合的类产生的对象所持有的方法
    release Fire skill
    猪头
   
   
 
** 接口** 

接口:提供了一个类的集合,可以把接口当作类函数的集合,让子函数去实现功能
归一化:基于同一个接口实现的类

**抽象类**

类是从一堆对象中抽取相同的内容,抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的。

** 在python中实现抽象类**

    #一切皆文件
    import abc #利用abc模块实现抽象类
    class All_file(metaclass=abc.ABCMeta):
        all_type='file'
        @abc.abstractmethod #定义抽象方法,无需实现功能
        def read(self):
            '子类必须定义读功能'
            pass

   
     class Txt(All_file):
         pass   
    t1=Txt()  # 程序报错
会报错是因为其在继承All_file类之后没有定义read的抽象方法,实现read功能,改正如下

    class Txt(All_file): #子类继承抽象类,但是必须定义read方法
        def read(self):
            print('文本数据的读取方法')
           
    wenbenwenjian=Txt()
    wenbenwenjian.read()
    print(wenbenwenjian.all_type)
   
**抽象类与接口**

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
  
  
**多态**

多态指的是一类事物有多种形态, 动物有多种形态:人,狗,猪

    import abc
    class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
        @abc.abstractmethod
        def talk(self):
            pass
   
    class People(Animal): #动物的形态之一:人
        def talk(self):
            print('say hello')
   
    class Dog(Animal): #动物的形态之二:狗
        def talk(self):
            print('say wangwang')
   
    class Pig(Animal): #动物的形态之三:猪
        def talk(self):
            print('say aoao')

**多态性**

指在不考虑实例类型的情况下使用实例,多态性分为静态多态性和动态多态性
多态性好处
1 增加了程序的灵活性
2 增加了程序额可扩展性

静态多态性:如任何类型都可以用运算符+进行运算
   
   
动态多态性:如下

    peo=People()
    dog=Dog()
    pig=Pig()
   
    #peo、dog、pig都是动物,只要是动物肯定有talk方法
    #于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
    peo.talk()
    dog.talk()
    pig.talk()
   
    #更进一步,我们可以定义一个统一的接口来使用
    def func(obj):
        obj.talk()

**鸭子类型 **  

Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’

python程序员通常根据这种行为来编写程序。

例如,如果想编写现有对象的自定义版本,可以继承该对象
也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。

    class TxtFile:
        def read(self):
            pass
   
        def write(self):
            pass
   
    class DiskFile:
        def read(self):
            pass
        def write(self):
            pass

**封装**

隐藏

在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

    #其实这仅仅这是一种变形操作
    #类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:
   
    class A:
        __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
        def __init__(self):
            self.__X=10 #变形为self._A__X
        def __foo(self): #变形为_A__foo
            print('from A')
        def bar(self):
            self.__foo() #只有在类内部才可以通过__foo的形式访问到.
   
    #A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
   
自动变形的特点:

类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。

这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
   
   
   
        #把fa定义成私有的,即__fa
    >>> class A:
    ...     def __fa(self): #在定义时就变形为_A__fa
    ...         print('from A')
    ...     def test(self):
    ...         self.__fa() #只会与自己所在的类为准,即调用_A__fa
    ...
    >>> class B(A):
    ...     def __fa(self):
    ...         print('from B')
    ...
    >>> b=B()
    >>> b.test()
    from A
    self.__fa()变成_A__fa,fa只在A类内部使用,如果是self.fa(),则返回到对象b里使用。