python 中面向对象的基础
面向对象的三大特征:继承、封装和多态
封装:把内容封装到某个地方,便于后面使用; 对于封装,其实就是使用初始化构造方法将内容封装到对象中,然后通过对象直接或者self来获取被封装的内容;
继承:儿子可以继承父亲的内容【属性和行为】(爸爸有的儿子都有,但是儿子有的爸爸不一定有);
多态:定义时的类型和运行时的类型不一样,此时就成为多态;
单继承
class Animal: # 父类
def eat(self):
print('吃饭')
pass
def drink(self):
pass
pass
class Dog(Animal): # 继承 Animal -- 只需要类名后面的小括号()中写上父类的名字,那么父类的属性、方法,会被继承给子类
def wwj(self):
print('小狗汪汪叫')
pass
pass
class Cat(Animal): # 继承 Animal -- 父类的属性、方法,会被继承给子类
def mmj(self):
print('小猫喵喵叫')
pass
pass
d1=Dog()
d1.eat() # 继承了父类的行为 -- # 单继承,只用关注不一样的就行了,一样的就用父类继承过来
d1.wwj()
c1=Cat()
c1.eat() # 继承了父类的行为
c1.mmj()
多继承
子类可以继承一个父类,那是否可以继承两个父类或多个呢? 答案是肯定的,这就是python的多继承;
C 类可以继承 A、B 两个类,可以将 A, B 中的方法继承过来,C 拥有 A,B 的方法和属性,class C(A, B)
;
如果在上面的 A 类和 B 类中,有一个同名的方法,那么通过子类去调用的时候, 查找顺序是:
先在 C 中找 -> 没有 -> 去 A 中找 -> 再没有 -> 去 B 中找 -> B有输出,查找中断,不再继续 -> 若 B 中也没有会报错;
class D():
def eat(self):
print('D.eat')
class C(D):
def eat(self):
print('c.eat')
class B(D):
def eat(self):
print('B.eat')
class A(B,C): # 多继承
pass
a = A()
a.eat() # 执行 eat 时,查找的顺序是:A -> B -> C -> D
print(A.__mro__) # 查询查找的顺序,也是继承的顺序,若是都有同名方法的话,那就是重载了 -- 为了方便且快速地看清 继承 关系和顺序,可以用__mro__方法
继承的传递
类的传递过程中,我们又把父类称为基类,子类又称为派生类,父类的属性和方法可以一级一级的传递到子类,子类可以继承父类的父类的方法和属性;
class Grandfather:
def eat(self):
print('吃饭')
class Father(grandfather):
pass
class Son(father):
pass
s=Son()
s.eat()
print(Son.__mro__)
重写父类方法
子类中,有一个和父类相同名字的方法,在子类中的方法会覆盖掉父类中同名的方法;通常都是父类方法已经不能满足子类的需求,需要重写或完善父类;
class Dog:
def bark(self):
print('汪汪叫')
class Keji(Dog):
def bark(self): # 重写父类方法
print('像小猫一样叫。')
kj = Keji()
kj.bark()
调用父类方法--继承+扩展
若子类中将有一个方法需要父类的功能,并且在此之上添加新的功能;如果直接重写父类方法,那么就要重复写很多代码,这里可以先调用父类方法再添加新的;
class Dog:
def __init__(self,name,color):
self.name = name
self.color = color
def bark(self):
print('汪汪叫')
class Keji(Dog):
def __init__(self,name,color): # 重写父类的方法
# Dog.__init__(self,name,color) # 1、手动调用父类的方法,执行完毕就可以具备 name 和 color 这两个实例属性了
super().__init__(name,color) # 2、自动调用,会自己找到对应的父类 self,多个父类的时候会按照顺序查找
self.height=90 # 3.扩展其他属性
self.weight=20
def __str__(self):
return '{}的颜色是{},它的身高是{}cm,体重是{}公斤'.format(self.name,self.color,self.height,self.weight)
def bark(self): # 属于重写父类方法
print('像小猫一样叫。')
kj = keji('柯基犬','红色')
kj.bark()
print(kj)
多态--多种形态
又称鸭子模型,定义时的类型和运行时的类型不一样,对同一种行为,不同的子类【对象】有多种不同的表现
两个前提:1.继承:必须存在继承关系,必须在父类和子类之间;2.重写:子类重写父类的方法;
多态的优势:增加程序的灵活性;增加程序的扩展性;
class Animal: # 父类
def say_who(self): # 说话的行为
print('我是一只动物')
class duck(Animal): # 子类:鸭子类
def say_who(self): # 子类重写父类的方法
print('我是一只鸭子')
class dog(Animal): # 子类:小狗类
def say_who(self):
print('我是一只小狗')
class cat(Animal): # 子类:小猫类
def say_who(self):
print('我是一只小猫')
print('*****重写调用****')
yz=duck()
yz.say_who()
xg=dog()
xg.say_who()
xm=cat()
xm.say_who()
print('********循环调用(多态的优势)****') # 新增子类更方便
class bird(Animal): # 子类:小鸟类
def say_who(self):
print('我是一只小鸟')
def commmon(obj): # 多态可以有个 统一调用的方法
'''
:param obj: 对象的实例
:return:
'''
obj.say_who()
listobj = [duck(), dog(), cat(), bird()]
for i in listobj:
commmon(i) # 我是一只鸭子, 我是一只小狗, 我是一只小猫, 我是一只小鸟