• Python-面向对象之单继承


    、基本概念

      面向对象三要素之一:继承inheritance

      继承表达式:class Cat(Anaimal),继承可以让子类从父类获取特征(属性和方法)

      父类:Anaimal 就是Cat的父类,也称为基类,超类

      子类:Cat就是Anaimal的子类,也称为派生类

    2、定义

      格式如下:

    class 子类名(父类名):
        语句块

      如果类定义时,没有基类列表,等同于继承自object,在Python3中,object类是所有对象的根基类

    只在python3 中是可以等价的,python2中不同的
    class
    A: pass 等同于 class A(object): pass  

      注意:python支持多继承,继承也可以多级。

        查看继承的特殊属性和方法有:

    特殊属性和方法 含义 示例
    __base__ 类的基类  
    __bases__ 类的基类元组  
    __mor__ 显示方法查找顺序,基类的元组  
    mro()方法 同上,返回列表  
    __subclassedd__() 类的子类列表
    print(Anaimal.__subclasses__())

     3、继承中的访问控制:

      举例:

     1 class Anaimal:
     2     __COUNT = 100
     3     HEIGHT = 0
     4 
     5     def __init__(self, age, weight, height):
     6         self.__COUNT += 1
     7         self.age = age
     8         self.__weight = weight
     9         self.HEIGHT = height
    10 
    11     def eat(self):
    12         print('{} eat'.format(self.__class__.__name__))
    13 
    14     def __getweight(self):
    15         print(self.__weight)
    16 
    17     @classmethod
    18     def showcount1(cls):
    19         print(cls)
    20         print(cls.__dict__)
    21         print(cls.__COUNT)
    22 
    23     @classmethod
    24     def __showcount2(cls):
    25         print(cls.__COUNT)
    26 
    27     def showcount3(self):
    28         print(self.__dict__)
    29         print(self.__COUNT)
    t1.py
     1 from t1 import Anaimal
     2 
     3 class Cat(Anaimal):
     4     NAME = 'CAT'
     5     __COUNT = 200
     6 
     7 # c = Cat()  缺参数,报错
     8 c = Cat(3, 5, 15)# 使用父类初始化函数进行初始化
     9 # print(c.HEIGHT) # 自己没有,调用父类的属性
    10 # c.eat()# 调用父类的方法
    11 # print(c._Anaimal__weight)# 获取父类初始化函数中的属性
    12 # c._Anaimal__getweight()
    13 
    14 c.showcount3()
    t2.py

     

     

     

      总结:

    1. 从父类继承,自己没有的,就可到父类中找
    2. 私有的都是不可以访问的,但是本质上依然是改了名称放在这个属性所在类或示例的__dict__中,知道这个名称就可以直接找到这个隐藏的变量,这个是黑魔法,慎用
    3. 继承时,公有的,子类和实例都可以随意访问,私有成员被隐藏,子类和实例不可直接访问,但私有变量所在的类内的方法可以访问这个私有变量
    4. Python通过自己一套实现,实现和其他语言一样的面向对象的继承机制
    5. 私有的只个自己用,并不是给其他的类或实例用的,出去的,也就是可以直接在类外调用的,都是共有的
    6. 事实上,在类内部是可以随便访问的,直接  .__xx 调用的,但事实上,在外部,看到的不是这个名字
    7. 如果想获取私有属性,可以给一个调用方法 如:getage 返回 self.__age,或者使用属性装饰器property,从而不需要知道隐藏属性的真是名称,直接访问
    8. 私有方法,就不要调来调去了,虽然是可以的!

      属性查找顺序:

         实例的__dict__ ----> 类的 __dict__ ---> 如果有继承 -----> 父类的__dict__

          如果一直没找到,抛异常,找到了,立即返回

    4、方法的重写、覆盖override 

      举例: 

     1 class Anaimal:
     2     def shout(self):
     3         print('Animal')
     4 
     5 class Cat(Anaimal):
     6     def shout(self):
     7         print(super())
     8         print(super(Cat, self))
     9         super().shout()
    10         super(Cat, self).shout()
    11         self.__class__.__base__.shout(self)
    12         print('miao')
    13 
    14 # a = Anaimal()
    15 # a.shout()
    16 c = Cat()
    17 c.shout()
    18 # print(a.__dict__)
    19 # print(c.__dict__)
    20 # print(Anaimal.__dict__)
    21 # print(Cat.__dict__)
    举例

      对于类方法和静态方法也是一样的:

     1 class Animal:
     2     @classmethod
     3     def class_method(cls):
     4         print('class_Animal')
     5 
     6     @staticmethod
     7     def static_method():
     8         print("static_Animal")
     9 
    10 class Cat(Animal):pass
    11     # @classmethod
    12     # def class_method(cls):
    13     #     print('class_Cat')
    14     #
    15     # @staticmethod
    16     # def static_method():
    17     #     print("static_Cat")
    18 
    19 c = Cat()
    20 c.class_method()
    21 c.static_method()

       

    5、继承中的初始化

      举例:

     

      从上面的代码可以看出:

        如果类B 定义时声明继承 类A,则在类B 中__bases__中是可以看到类A的,但是这和是否调用类A 的构造方法时两回事

        如果B中调用了A 的构造方法,就可以拥有父类的属性了,

      举例

     1 class A:
     2     def __init__(self, a, d=10):
     3         self.__d = d
     4         self.a = a
     5 
     6 class B(A):
     7     def __init__(self, b, c):
     8         super().__init__(b+c, b-c)
     9         # 等价 A.__init__(self, b+c, b-c)
    10         self.b = b
    11         self.c = c
    12 
    13     def printv(self):
    14         print(self.b)
    15         print(self.a)
    16         print(self._A__d)
    17 
    18 f = B(200, 300)
    19 print(f.__dict__)
    20 print(f.__class__.__bases__)
    21 f.printv()
    View Code

       

        总结:

          作为好习惯,如果分类定义了__init__方法,要在子类的__init__中调用它。显式的调用

        除非:子类没有定义__init__,会隐式去调用或者继承父类的__init__,子类一旦定义了__init__,就不会自动调用父类的init

      

      如何正确的初始化: 

     1 class Animal:
     2     def __init__(self, age):
     3         print('Animal')
     4         self.age = age
     5 
     6     def show(self):
     7         print(self.age)
     8 
     9 class Cat(Animal):
    10     def __init__(self, age, weight):# 没有调用父类的init,这就导致没有实现继承效果
    11         print('Cat')       
    12         self.age = age + 1
    13         self.weight = weight
    14 
    15 c = Cat(10, 5)
    16 print(c.__dict__)
    17 c.show()
    18 
    19 print('-' * 30)
    20 class Animal:
    21     def __init__(self, age):
    22         print('Animal')
    23         self.age = age
    24 
    25     def show(self):
    26         print(self.age)
    27 
    28 
    29 class Cat(Animal):
    30     def __init__(self, age, weight):
    31         print('Cat')
    32         super().__init__(age)
    33         self.age = age + 1 # 覆盖之前的self.age
    34         self.weight = weight
    35 
    36 
    37 c = Cat(10, 5)
    38 print(c.__dict__)
    39 c.show()
    40 
    41 
    42 print('-' * 30)
    43 class Animal:
    44     def __init__(self, age):
    45         print('Animal')
    46         self.age = age
    47 
    48     def show(self):
    49         print(self.age)
    50 
    51 
    52 class Cat(Animal):
    53     def __init__(self, age, weight):
    54         print('Cat')
    55         self.age = age + 1
    56         self.weight = weight
    57         super().__init__(age)
    58 
    59 
    60 c = Cat(10, 5)
    61 print(c.__dict__)
    62 c.show()
    注意init出现的位置
     1 Cat
     2 {'age': 11, 'weight': 5}
     3 11
     4 ------------------------------
     5 Cat
     6 Animal
     7 {'age': 11, 'weight': 5}
     8 11
     9 ------------------------------
    10 Cat
    11 Animal
    12 {'age': 10, 'weight': 5}
    13 10
    结果打印

      例子中打印10 的,原因看__dict__ 就知道了,因为父类Animal的show方法中_age会被释放为_Animal__age,因此。显式10,而不是11,这样的设计不会,子类应该显式自己的属性值最好

      解决办法:

          一个原则,自己的私有属性,就该自己的方法读取和修改,不要借助其他类的方法,即使是父类或者派生类。

    为什么要坚持,想一想当初!
  • 相关阅读:
    学习两个Python不常用的语法
    使用uwsgi在centos7上部署Flask在线Web服务
    redis server学习002
    上传至gitlab—— 本地git出现fatal: The current branch develop has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin develop 的问题
    数据库脏数据——数据库中的并发操作带来的一系列问题
    error: failed to push some refs to 'git@github.com:Sirxy/flask_jwt_demo.git'
    redis server学习001
    【解决方案】麒麟v10,更新yum源
    【解决方案】github图片加载不出来
    linux c程序高cpu,排查记录
  • 原文地址:https://www.cnblogs.com/JerryZao/p/9657055.html
Copyright © 2020-2023  润新知