面向对象三大特点,类的继承

三大特点

  • 封装:既是对数据的封装,又是对处理数据方法的封装。
  • 继承:强调父子类的关系
  • 多态:不同的对象调用相同的方法,有不同的响应

类的继承

  • 相关概念
    • 继承:父类的属性和方法,子类直接拥有,称为继承。
    • 派生:子类在父类的基础上衍生出的新的特征(属性和行为)。
    • 总结:其实他们是一回事,只是描述问题的侧重点不同(继承侧重相同点,派生侧重不同点)
  • 继承与派生
    • 继承
    # class Animal:
    # 当没有写父类时,默认继承自object类
    class Animal(object):
        def __init__(self, name):
            self.name = name
    
        def run(self):
            print('很多小动物喜欢到处奔跑')
            
    class Dog(Animal):
        pass
    
    d = Dog('旺财')
    
    # 直接拥有父类的属性
    print(d.name)
    
    # 直接拥有父类的方法
    d.run()
  • 派生
    class Animal:
        def run(self):
            print('小动物喜欢到处乱跑')
    
    class Cat(Animal):
        def eat(self):
            print('俺喜欢吃鱼')   
    
    c = Cat()
    
    # 继承自父类的方法
    c.run()
    
    # 衍生的方法
    c.eat()
    
    # 动态添加的属性
    c.name = '加菲'
    print(c.name)  
  • 方法重写
    class Animal:
        def eat(self):
            print('小动物一天到晚吃个不停')
    
        def run(self):
            print('天天到处乱跑')
    
    class Cat(Animal):
        # 完全不合适,需要覆盖重写
        def run(self):
            print('俺走的是猫步')
    
        # 不是完全合适,需要进行修改
        def eat(self):
            # 调用父类的方法
            # Animal.eat(self)        # 不建议使用
            # super(Cat, self).eat()    # 老的写法
            super().eat()               # 新的写法,推荐使用
            print('俺喜欢吃鱼')   
            
    c = Cat()
    
    c.run()
    c.eat()
  • 多继承:一个类可以有多个父类
    • 基本语法
    class A:
        def eat(self):
            print('eat func in class A')
            
    class B:   
        def run(self):
          print('run func in class B')
    
        def eat(self):
            print('eat func in class B')
    
    # 多继承,多个父类之间使用逗号隔开
    class C(A, B):
        def eat(self):
            # 不重写或直接使用super,都是采用的默认继承顺序
            # super().eat()
            # 明确指定调用哪个父类的方法
            B.eat(self)
            
    c = C()
    
    c.eat()
    c.run() 
  • 继承链的顺序
    class A(object):
        def foo(self):
            print('A foo')
            
    class B(object):
        def foo(self):
            print('B foo')
    
        def bar(self):
            print('B bar')
            
    class C1(A, B):
        pass   
        
    class C2(A, B):
        def bar(self):
            print('C2-bar')
            
    class D(C1, C2):
        pass
    
    d = D()
    
    d.foo()
    d.bar()
        
    # __mro__类属性,记录了继承连的查找顺序
    # 一旦找到,立即停止并返回
    # 采用的是广度优先遍历的原则
    for i in D.__mro__:
        print(i)
  • 访问权限
    class Person:
        def __init__(self, name, age):
            self.name = name
            self.age = age
            self.__money = 100
    
        def test(self):
            print('for test', self.__money)
            
    p = Person('王大花', 18)
    
    # 公有属性:在类内、类外以及子类中都可以使用
    print(p.name)
    
    # 私有属性:只能在类的内部使用,类外及子类中都不能使用
    # print(p.__money)
    
     p.test()
    print(p.__dict__)
    
    # 实现:在原有的属性名之前添加了'_类名'的前缀
    # 不建议这样使用
    # print(p._Person__money)
    
    class Man(Person):
        def introduce(self):
            print(self.name, self.age)
            # print(self.__money)
            
    m = Man('二狗', 20)
    print(m.name)
    m.test()
  • 总结:
    • 公有属性:在类的内部、外部、子类中都可以使用
    • 私有属性:只能在类的内部使用,不能在外部及子类中使用
    • 实现原理:默认在以__开头的属性前添加了_类名的前缀
  • 类属性
    class Person:
        # 类属性:通过类名进行访问
        nation = '中国'
    
        # 限制对象可以使用的属性,可以大幅提升访问的效率
        __slots__ = ('name', 'age')
    
        def __init__(self, name):
            self.name = name
            
    xiaoming = Person('小明')
    xiaohong = Person('小红')
    
    print(xiaoming.name)
    print(xiaohong.name)
     
    # 访问类属性,通过类名访问
    print(Person.nation)
    
    # 不要这样使用
    # print(xiaoming.nation)
    
    # 查看对象的类型
    print(xiaoming.class)
    
    # 特殊的类属性
    # 类的名字
    print(Person.__name__)
    
    # 父类组成的元组
    print(Person.__bases__)
    
    # 类相关的信息
    print(Person.__dict__)
    
    # 继承链查找顺序
    print(Person.__mro__)
    
    # print(Person.slots)
    # 不能添加,因为slots中没有改属性
    # xiaoming.weight = 180
  • 类方法
    • 说明:也是通过类名调用,创建时需要使用装饰器classmethod
    • 创建对象或简单的创建对象
    class Person:
        # 成员方法,通过对象调用
        def eat(self):
            print('能吃是福')
    
        # 类方法,通过类名调用
        @classmethod
        def test(cls):
            # cls表示当前类
            print(cls)
    
        # 创建对象 或 简单的创建对象
        @classmethod
        def create(cls):
            p = cls()
            p.age = 1
            return p
        
    p = Person()
    p.eat()
    
    Person.test()
    
    p2 = Person.create()
    print(p2.age, type(p2))
  • 提供简洁易用的对外接口
      class Number:
          def __init__(self, num1, num2):
              self.num1 = num1
              self.num2 = num2
    
          def add(self):
              return self.num1 + self.num2
    
          def sub(self):
              return self.num1 - self.num2
    
          def mul(self):
              return self.num1 * self.num2
    
          def div(self):
              if self.num2 == 0:
                  return None
              return self.num1 / self.num2
    
          @classmethod
          def pingfanghe(cls, num1, num2):
              n1 = cls(num1, num1)
              n12 = n1.mul()
    
              n2 = cls(num2, num2)
              n22 = n2.mul()
    
              n3 = cls(n12, n22)
              return n3.add()
    
    # 直接调用类方法
    print(Number.pingfanghe(3, 4))        
  • 静态方法
    • 说明:也是通过类型调用,使用装饰器staticmethod装饰
    • 示例:
    class Person:
        # 定义静态方法
        @staticmethod
        def test():
            print('for test')
    
        # 可以创建对象
        @staticmethod
        def create():
            p = Person()
            return p
     
    class Man(Person):   
        @staticmethod
        def test():
            # 无法调用父类的方法
            # super().test()
            print('xxx')
            
    Person.test()
    
    p = Person.create()
    print(type(p))
    
    Man.test()
  • 总结
    • 凡是使用静态方法解决的问题都可以使用类方法进行解决
    • 静态方法重写时无法调用父类的方法
    • 静态方法中没有cls的参数
分类: Python编程

发表评论 X

电子邮件地址不会被公开。 必填项已用*标注

姓名不能为空
填写正确的email