面向对象三 继承、方法重写、super()、多重继承、多态

面向对象下 继承、方法重写、super()、多重继承、多态

一、继承简介
  • 继承是面向对象三大特性之一

  • 作用:通过继承可使一个类获取到其他类中的属性和方法

  • 在定义类时,可以在类名后的括号中指定当前类的父类(超类、基类)

  • 继承提高了类的复用性,让类与类产生了关系。

  • 有了继承这个特性,才有了多态的特性

    • class Animal:
          def run(self):
              print('动物会跑。。。。。')
          def sleep(self):
              print('动物睡觉。。。。。')
      
      class Dog(Animal): # 类里无代码,可调用父类的方法
          pass
      
      d = Dog()
      d.run()
      d.sleep()
      
      # 动物会跑。。。。。
      # 动物睡觉。。。。。
      
      class Animal:
          def run(self):
              print('动物会跑。。。。。')
          def sleep(self):
              print('动物睡觉。。。。。')
      
      class Dog(Animal):	# 除继承父类外,也可有Dog类独有的方法
          def speak(self):
              print('汪汪汪汪。。。。。')
      
      d = Dog()
      d.run()
      d.sleep()
      d.speak()
      # 动物会跑。。。。。
      # 动物睡觉。。。。。
      # 汪汪汪汪。。。。。
      
      class Animal:
          def run(self):
              print('动物会跑。。。。。')
          def sleep(self):
              print('动物睡觉。。。。。')
      
      class Dog(Animal):
          def speak(self):
              print('汪汪汪汪。。。。。')
      
      d = Dog()
      
      r = isinstance(Dog,Animal)
      r1 = isinstance(d,Animal) # 判断d是否是Animal的实例
      r2 = isinstance(d,Dog)
      print(r,r1,r2)
      # False True True
      
      
      # 在创建类的时候,如果省略了父类,则默认父类是object
      # object是所有类的父类,所有类都继承于object
      class Person:
          pass
      # issubclass() 检测一个类是否是另一个类的子类
      r = issubclass(Dog,Animal)
      r1 = issubclass(Dog,Person)
      r3 = issubclass(Animal,object)
      r4 = issubclass(Person,object)
      r5 = issubclass(int,object)
      print(r, r1,r3,r4,r5)
      # True False True True True
      
      class Animal:
          def run(self):
              print('动物会跑。。。。。')
          def sleep(self):
              print('动物睡觉。。。。。')
      
      class Dog(Animal):
          def run(self):
              print('狗会跑。。。。。')
          def speak(self):
              print('汪汪汪汪。。。。。')
      
      d = Dog()
      d.run()
      # 狗会跑。。。。。
      
二、 方法重写
  • 如果在子类有和父类同名的方法,则通过子类实例去调用方法时,会调用子类的方法而非父类的方法,这个特点称之为方法的重写(覆盖,override)

  • 当调用一个对象的方法时:

    • 会优先去当前对象中寻找是否具有该方法,如有则直接调用

    • 如果没有,则去当前对象的父类中寻找,如父类也有则直接调用父类中的方法

    • 如还没有,则去父类的父类中寻找,以此类推,直到找到object,如依然没有则报错

      • class Animal:
            def run(self):
                print('动物会跑。。。。。')
            def sleep(self):
                print('动物睡觉。。。。。')
        
        class Dog(Animal):
            def run(self):
                print('狗会跑。。。。。')
            def speak(self):
                print('汪汪汪汪。。。。。')
        
        d = Dog()
        d.run()
        # 狗会跑。。。。。
        
        class A():
            def test(self):
                print('A.....')
        class B(A):
            pass
        class C(B):
            pass
        c = C()
        c.test()
        # A.....
        
        class A():
            def test(self):
                print('A.....')
        class B(A):
            def test(self):
                print('B.....')
        class C(B):
            pass
        c = C()
        c.test()
        # B.....
        
        class A():
            def test(self):
                print('A.....')
        class B(A):
            def test(self):
                print('B.....')
        class C(B):
            def test(self):
                print('C.....')
        c = C()
        c.test()
        # C.....
        
三、super()
  • Super() 可以获取到当前类的父类

  • 通过super() 返回对象调用父类方法时,不需要传递self

  • # 父类所有的方法(包括特殊方法)都会被子类继承
    class Animal:
        def __init__(self,name):
            self._name = name
    
        def run(self):
            print('动物会跑。。。。。')
        def sleep(self):
            print('动物睡觉。。。。。')
    
        @property
        def name(self):
            return self._name
    
        @name.setter
        def name(self, name):
            self._name = name
    
    class Dog(Animal):
        def run(self):
            print('狗会跑。。。。。')
        def speak(self):
            print('汪汪汪汪。。。。。')
    
    # d = Dog() # TypeError: __init__() missing 1 required positional argument: 'name'
    d = Dog('金毛')   # 金毛
    d = Dog('秋田')   # 秋田
    print(d.name)
    
    class Animal:
        def __init__(self,name):
            self._name = name
    
        def run(self):
            print('动物会跑。。。。。')
        def sleep(self):
            print('动物睡觉。。。。。')
    
        @property
        def name(self):
            return self._name
    
        @name.setter
        def name(self, name):
            self._name = name
    
    class Dog(Animal):
        def __init__(self,name,age):
            self._name = name
            self._age = age
        def run(self):
            print('狗会跑。。。。。')
        def speak(self):
            print('汪汪汪汪。。。。。')
    
        @property
        def age(self):
            return self._age
        @age.setter
        def age(self,age):
            self._age = age
    
    # d = Dog('金毛')   # TypeError: __init__() missing 1 required positional argument: 'age'
    d = Dog('金毛',8)   # 金毛 8
    print(d.name,d.age)
    
    # 如果父类的属性较多
    class Animal:
        def __init__(self,name):
            self._name = name
    
        def run(self):
            print('动物会跑。。。。。')
        def sleep(self):
            print('动物睡觉。。。。。')
    
        @property
        def name(self):
            return self._name
    
        @name.setter
        def name(self, name):
            self._name = name
    
    class Dog(Animal):
        # 希望直接调用父类的__init__方法来初始化父类中定义的属性
        def __init__(self,name,age):
            Animal.__init__(self,name) 
            self._age = age
        def run(self):
            print('狗会跑。。。。。')
        def speak(self):
            print('汪汪汪汪。。。。。')
    
        @property
        def age(self):
            return self._age
        @age.setter
        def age(self,age):
            self._age = age
    
    # d = Dog('金毛')   # TypeError: __init__() missing 1 required positional argument: 'age'
    d = Dog('金毛',8)   # 金毛 8
    print(d.name,d.age)
    
    
    class Animal:
        def __init__(self,name):
            self._name = name
    
        def run(self):
            print('动物会跑。。。。。')
        def sleep(self):
            print('动物睡觉。。。。。')
    
        @property
        def name(self):
            return self._name
    
        @name.setter
        def name(self, name):
            self._name = name
    
    class Dog(Animal):
        # 希望直接调用父类的__init__方法来初始化父类中定义的属性
        # super() 动态获取当前类的父类,通过super()调用父类方法时,不须传入self
        def __init__(self,name,age):
            super().__init__(name)
            self._age = age
        def run(self):
            print('狗会跑。。。。。')
        def speak(self):
            print('汪汪汪汪。。。。。')
    
        @property
        def age(self):
            return self._age
        @age.setter
        def age(self,age):
            self._age = age
    
    d = Dog('金毛',8)   # 金毛 8
    print(d.name,d.age)
    
四、 多重继承
  • 在python中是支持多重继承的。可以为一个类同时制定多个父类

  • 可以在类名的()中添加多个类,来实现多重继承

  • 多重继承,会使子类同时拥有多个父类,并会获取到所有父类的方法

  • 在开发中没有特殊情况,应尽量避免使用多重继承,因为多重继承会让我们的代码更加复杂

  • 如果多个父类中有同名的方法,则会先在第一个父类中寻找,然后找第二个,第三个。。。前面的会覆盖后面的

  • # __bases__方法,可以获取当前类所有的父类
    # python 是支持多重继承的,可以为一个类指定多个父类
    class A():
        def test(self):
            print('A.....')
    class B():
        def test(self):
            print('B.....')
    class C(B):
        pass
    print(C.__bases__)      # (<class '__main__.B'>,)
    print(B.__bases__)      # (<class 'object'>,)
    print(int.__bases__)    # (<class 'object'>,)
    
    
    class A():
        def test(self):
            print('A.....')
    class B():
        def test(self):
            print('B.....')
    class C(A,B):
        pass
    print(C.__bases__)      # (<class '__main__.A'>, <class '__main__.B'>)
    c = C()
    c.test()        #  A.....
    
    class A():
        pass
    class B():
        def test(self):
            print('B.....')
    class C(A,B):
        pass
    c = C()
    c.test()        #  B.....
    
五、多态
  • 多态是面向对象的三大特性之一

  • 一个对象可以以不同的形态去呈现

  • class A:
        def __init__(self,name):
            self._name = name
    
        @property
        def name(self):
            return self._name
        @name.setter
        def name(self,name):
            self._name = name
    class B:
        def __init__(self, name):
            self._name = name
        @property
        def name(self):
            return self._name
        @name.setter
        def name(self, name):
            self._name = name
    
    a = A('葫芦娃')
    b = B('一休哥')
    
    def speak(obj):
        print('你好%s'%obj.name)
    # speak2() 做了类型检查,只有obj是A类对象的情况,程序才给予执行
    # 其他类型的对象,无法使用该函数,这个函数违反了多态
    # 违反多态的函数,只适用于一种类型的对象,无法处理其他类型的对象,导致适用性差
    def speak2(obj):
        if isinstance(obj,A):   # 只有是A类才行
            print('你好%s' % obj.name)
    
    speak(a)    # 你好葫芦娃
    speak(b)    # 你好一休哥
    speak2(a)   # 你好葫芦娃
    speak2(b)   # 为空
    
    # 对象中有__len__特殊方法就可以使用len()来获取长度
    ls = [1,2,3,4,5,6,7]
    str = 'python'
    print(len(ls))      # 7
    print(len(str))     # 6
    
    class A:
        def __init__(self,name):
            self._name = name
        def __len__(self):
            return 100
    a = A('葫芦娃')
    print(len(a))		# 100
    
六、属性和方法
  • 属性

    • 类属性,直接在类中定义的属性

    • 类属性可以通过类或类的实例访问。但是类属性只能通过类对象修改,无法通过实例对象修改

      • class A:
            # 类属性,直接在类中定义的属性
            count = 20
        a = A()
        print(A.count)      # 20
        print(a.count)      # 20
        
        
        # 类属性无法通过实例对象修改
        class A:
            # 类属性,直接在类中定义的属性
            count = 20
        a = A()
        a.count = 0
        print(A.count)      # 20  这儿依然是20
        print(a.count)      # 0
        
        # 类属性只能通过类属性修改
        class A:
            # 类属性,直接在类中定义的属性
            count = 20
        a = A()
        A.count = 0
        print(A.count)      # 0
        print(a.count)      # 0
        
        
    • 实例属性,通过实例对象添加的属性属于实例属性

    • 实例属性只能通过实例对象访问和修改,类对象无法访问和修改

      • class A:
            # 类属性,直接在类中定义的属性
            count = 20
            def __init__(self):    # 实例属性,是通过实例对象添加的属性,self为当前对象,self等同于a
                self.name = '老大'
        a = A()
        print('A',A.name)   # AttributeError: type object 'A' has no attribute 'name'
        print('a',a.name)     # a 老大
        
  • 方法

    • 在类中定义,以self为第一个参数的方法都是实例方法

    • 实例方法被调用时,python会将调用对象以self传入

    • 实例方法可以通过类和类实例去调用

    • 当通过实例调用时,会自动将当前调用对象作为 self传入

    • 当通过类调用时,不会自动传递self,必须手动传递self

      • class A:
            # 实例方法
            def test(self):
                print('test。。。')
        a = A()
        b = A()
        a.test()       # test。。。
        A.test()       # TypeError: test() missing 1 required positional argument: 'self'
        A.test(a)      # test。。。
        A.test(b)      # test。。。
        
    • 类方法 以@classmethod 来修饰的方法,第一个参数是cls,cls 是当前类的对象

    • 类方法与实例方法的区别,实例方法第一个参数为self,类方法第一个参数为cls

    • 类方法可以通过类调用,也可通过实例方法调用

      • class A:
            count = 0
            # 实例方法
            def test(self):
                print('test。。。')
            # 类方法
            @classmethod
            def test2(cls):
                print('类方法 test2。。。',cls)
        a = A()
        a.test2()       # 类方法 test2。。。 <class '__main__.A'>
        A.test2()       # 类方法 test2。。。 <class '__main__.A'>
        
        # 类方法可调用类属性
        class A:
            count = 100
            # 类方法
            @classmethod
            def test2(cls):
                print('类方法 test2。。。',cls.count)
        a = A()
        a.test2()   # 类方法 test2。。。 100
        A.test2()   # 类方法 test2。。。 100
        
  • 静态方法

    • 在类中用@staticmethod来修饰的方法为静态方法

    • 静态方法不需要指定任何的默认参数,静态方法可通过类和实例调用

    • 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数

    • 静态方法一般都是些工具方法,和当前类无关

      • class A:
            @staticmethod
            def test3():
                print('静态方法 test3...')
        a = A()
        a.test3()   # 静态方法 test3...
        A.test3()   # 静态方法 test3...
        
七、总结
  • 面向对象三大特性:
    • 封装 确保对象中数据的安全
    • 继承 保证了对象的扩展性
    • 多态 保证了程序的灵活性
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值