面向对象三要素,封装,继承,多态
对于人来讲,个体是继承自父母的,前驱是两个,这种叫多继承,就不是单继承
动物类,下面是鸟类,这样就是单继承
个体继承自父母,继承了父类的特征也有母类的特征,也有自己的个性
动物类,shout叫
cat,也有shout叫的方法
a=Animal()加括号实例化
各自的shout各有不同
现在这两个好像没有什么关系
需要写继承,cat继承自animal,还是什么都没有变化
现在如果去掉,cat里面什么都没写,这样就复用起来了,继承的好处,就是直接拥有父类的特征(能力,动作,方法)
这回就各叫各的了
还可以定义个狗,这样就节省了很多代码
动物要按名字,这样每个动物都需要要改变
动物也需要给,用这种方式就可以全部放进去了
用这种方式可以大大减少代码
可以再添加一个属性,动物的年龄默认5岁
dog没有写任何东西,看来是真的存下来了,是从父类那继承 的东西
自己的age,优先找自己字典里的age
但是这样定义就有问题
自己定义优先用自己的
用属性试试
用property,name就当作是属性,cat类找不到这个属性,就向上找父类这里要
但是把这段注释掉,cat没有属性,问父类要,但是父类连一个实例都没有
看一下自己的字典,父类连实例都没有,自己不存谁给你存
狗猫可以不写代码,能从animal继承就从animal继承
animal称为cat的父类也称为基类,base,super超类
cat也是animal的子类,派生类,subclass
再写一个类,没有写继承谁,两个是相等的,再python3是同样的东西(做了一个调整所有的类都继承自object)
python2就不一样
object是所有一切皆对象的祖先
除了object,一切类继承自object跟基类,是再python3种,python2是两条线
继承也可以多级
** __mro__是最重要的,整个继承体系靠这个东西**
告诉你animal就是从object来的
car从animal上来
cat的base是animal,animal的base是谁
返回的类被放到元组中
mro,整个继承路线就出来了
也可以拿到列表
查看一下子类的问题
布尔型好像是int的子类
加的时候是用整型来计算的
按照规范方法是要断一下
classmethod竟然也有私有的,然后在私有里面又去访问私有
cat没有就要问animal要
能不能访问weight,weight是私有成员
找不到weight
私有的跟它所在的类相关
现在是调用不了这个方法的
而这个返回的是实例属性
应该这么写
c.showcount1应该是
**到底是100还是200
打印的是cat的字典,但是打印的count是100
**
但是__count是私有属性,上一级的字典偶这个_count
类属性其实也可以往上找的
当前实例调用这个方法是返回的这个实例的类型,不会定义在animal就显示anima
打印的cat字典,但是__count私有属性会发生改变_Cat__count
所以调用showcount1的时候,找cat的__count是找不到的,需要到类上去找
谁调用就是谁的类,cls,但是__count在原来的找不到就找到了父类里面
为什么是101,
101怎么来的,初始化调用init方法,首先需要self.__count +=1 (这个count是100还是200)前面是animal就是100
这个101是放的animal的前缀
这就是动态增加属性,增加到自己的小字典上去了
私有属性就是加了一个所谓的改名,搜索顺序和等号赋值的顺序是不变的
一切都在字典中,需要自己打印查看
私有是不想给你访问,但是本质上是改了名,放在这个属性或者类的字典里
其实保护的也相当于公有的,也可以随意访问,但是小心,赋值就是重新定义,看是给谁赋值属性,如果是赋值属性,无论是类还是实例,要么覆盖原来属性,要么新造一个属性出来
(可以理解私有的就是别人自己的,没想给你访问,子类尤其不能访问父类的私有属性,私有只是自己用,不给其他类使用)
私有方法还是成员变量都是隐藏的,子类和实例都不可被直接的访问
**私有在类的内部是可以任意访问的,出了类就不能了,可以造一个公有方法调用私有的来作为访问
再造一个例子试试
**
私有隐藏,就是想在类外面不随便暴露
暴露字典你才看得到,其他语言不暴露字典你就看不到
属性查找顺序,实例的字典找,找不到就找自己类的字典,如果有单一继承就找父类的字典,最终找不到就抛出异常
继承是为了复用,也需要有一点个性
虽然继承实现关系,但是也有父类有父类的方法,子类有子类的方法,子类可以体现出父类的不同,可以理解是一种多态,大家都是animal,但是大家有所不同
这两个是放在,在实例的字典中是没有的
这两个方法也是不同的地址,各自定义在各自的位置上,各自存放在各自的字典上
一般方法是定义在类的字典上的
这样就真的是覆盖掉前面了
super()相当于返回一个父类
三个shout是一样的
缺一个cat对象实例
super对象是没有shout的,因为没有完成堆实例的绑定
这两个是等价的
animal。shout()就缺少一个位置参数
要一个self即可
super不能这么写,缺失实例
super其实是一个类
在用的时候就认为super返回父类,不但可以访问父类还可以对实例进行捆绑
上面的方法python3可以写
super会自动去搜索,根据类的继承关系自动去搜索,当前实例或者当前类对应的父类方法
用这种方式,其实可以调用父类的方法
有的时候在覆盖的过程中,父类的方法用完,加上自己特性的东西
这两种是等价的
如果用自己的实例来访问,这样访问的是自己类的字典
用子类的实例来访问,肯定都是子类的,子类没有才有可能访问到父类
cat初始化需要传两个参数,但是shout还是animal的
只有b和c没有a
告诉你没有调用父类的构造方法
建立了一个b实例,到目前为止只有一个实例字典,self就只能代表f,
在f自己的实例字典内,应该abcd都在
a是怎么跑到f实例字典里面去的
首先,计算右边,做B的实例化
初始化后,调用init方法
super()是A
()括号里什么都没写,等于super(B,self)B的父类找到A,问A有没有init方法,下面的self传给上面的self、就是未来的f,在这个实例动态创建a属性
__d私有属性会改名_A__d但是归未来的f实例管理** __d私有属性会改名_A__d但是归未来的f实例管理**
下面调用printv,先找的是实例字典的字典,然会找到的是实例的类的字典,找完这个类字典,再找父类的字典
(实例只找自己的字典,然后再找类的字典)
调用父类的init方法给这个sel增加一些属性
这个self相当于为当前实例,借助了父类里面定义的方法通过super调用再为它填充一些属性,最后这些属性都归当前实例的
这时候其实下面的f还没有实例化完成
目前情况下,调转一下顺序也无所谓
调用父类的也可以这么写,这两个是一样的
init不调用父类的话,有可能实例化的时候属性都凑不齐,因为在继承的时候,认为这个属性就自然也有了,但是如果不这么调用的话,a和__d就没有
下面再printv用到self。a就会出问题了
所以初始化方法跟其他不一样,在python要求你显示调用,这是好的习惯,哪怕父类什么都没有写
从好的出发,最好调用一下父类的super
过程是先算右边,还没有把实例化赋值给b
**B上找不到,就去找父类A的init,传入的self就是未来的b,是b类型刚造好的实例
self.__a的前缀是
_A__a2,但是字典归B的字典管
**
谁里面定义的按照谁的字典走
要是都注释化,init就找object去了,init是无参的
这样调用就跟上面没有关系,这样就叫覆盖,未调用初始化方法
这就是调用了父类的初始化方法,A.init
这样跟animal的init就没什么关系
稍微做些改动
调整下顺序,就还是10
有些语言,这个super是一定要放在第一行,直接报错,一般都是先调用父类的init构造,再去调用下面
等式先算右边,这个时候还没有实例化完成
要想做点继承就使用父类造好的,就先调用父类的,否则你就直接弄
私有方法要调用,相当于子类的方法覆盖父类的方法
自己的私有属性就自己使用
初始化的时候进尽量调用父类的,pycharm这样的工具会提醒你调用super
初始化中经常会调用父类的初始化方法来完成一些重复性的构造