![image](https://img2020.cnblogs.com/blog/2577469/202112/2577469-20211206202747757-1894215832.jpg)
一、面向对象的三大特征
-
封装:封装指的就是把数据与功能都整合到一起,听起来是不是很熟悉,没错,我们之前所说的”整合“二字其实就是封装的通俗说法。
-
继承
1. 什么是继承?
# 继承就是新建类的一种方式,新建的类我们称为子类或者叫派生类,被继承的类我们称为父类或者基类
# 子类可以使用父类中的属性或者方法
2. 为什么要用继承?
类解决了对象与对象之间的代码冗余问题
继承解决的是类与类之间的代码冗余问题
3. 如何使用继承?
新式类:继承了object类的子子孙孙类都是新式类
经典类:没有继承了object类的子子孙孙类都是经典类
# 新式类和经典类只有在python2中区分
继承:类与类之间的继承指的是什么’是’什么的关系(比如人类,猪类,猴类都是动物类)。子类可以继承/遗传父类所有的属性,因而继承可以用来解决类与类之间的代码重用性问题。比如我们按照定义Student类的方式再定义一个Teacher类
class Student: # 定义学生类
school = "南京校区" # 冗余共同属性
def __init__(self,name,age,gender): # 学生类与老师类有冗余部分
self.name = name
self.age = age
self.gender = gender
def choose(self):
print("%s 选课成功" %self.name)
stu1 = Student("jack",18,"male")
stu2 = Student("tom",19,"male")
stu3 = Student('lili',29,"female")
class Teacher: # 定义老师类
school = "南京校区"
def __init__(self,name,age,gender,level): # 老师类与学生类功能多一个level
self.name = name
self.age = age
self.gender = gender
self.level = level
def score(self):
print("%s 正在为学生打分" %self.name)
tea1 = Teacher('hxx',18,"male",10)
tea2 = Teacher('lxx',38,"male",3)
从上面看出:类Teacher与Student之间存在重复的代码,老师与学生都是人类,所以我们可以得出如下继承关系,实现代码重用
class Foo:
def __f1(self): # _Foo__f1()
print('Foo.f1') # 2打印
def f2(self):
#
print('Foo.f2') # 1 打印
self.__f1() # _Foo__f1()
class Bar(Foo):
def __f1(self): # # _Bar__f1()
print('Bar.f1')
'''
会先从 自己本身Bar找f2 如果没有 ,就会去父类找,找到了f2 ,f2里面又执行了双下f1
为隐藏属性,隐藏属性的特征 在定义的时候 就直接定义好了
'''
obj = Bar() # {}
obj.f2()
# 新式类:按照广度优先查询
# 经典类:按照深度优先查询
class A(object):
def test(self):
print('from A')
class B(A):
# def test(self):
# print('from B')
pass
class C(A):
# def test(self):
# print('from C')
pass
class D(B):
# def test(self):
# print('from D')
pass
class E(C):
# def test(self):
# print('from E')
pass
class F(D, E):
# def test(self):
# print('from F')
pass
f1 = F()
f1.test()
1、继承的实现原理
Python中子类可以同时继承多个父类,如A(B,C,D)
如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性
如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先
![img](https://img2020.cnblogs.com/blog/2240626/202101/2240626-20210112195816023-176936865.png)
![img](https://img2020.cnblogs.com/blog/2240626/202101/2240626-20210112195827583-221856927.png)
二、super()和mro()列表
-
方式二: super()返回一个特殊的对象,该对象会参考发起属性查找的那一个类的mro列表,去当前类的父类中找属性,严格依赖继承
class People:
school = "南京校区"
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
class Teacher(People):
# 空对象,'hxx',18,"male",10
def __init__(self,name,age,gender,level):
# People.__init__(self,name,age,gender)
super(Teacher,self).__init__(name,age,gender)
self.level = level
def score(self):
print("%s 正在为学生打分" %self.name)
tea1 = Teacher('hxx',18,"male",10) # 空对象,'hxx',18,"male",10
print(tea1.__dict__)
# 案例:
class A: # [A,object]
def test(self):
print("from A")
super().test()
class B:
def test(self):
print('from B')
class C(A,B): # [C,A,B,object]
pass
# obj=C()
# obj.test()
obj1 = A()
obj1.test()
![image](https://img2020.cnblogs.com/blog/2577469/202112/2577469-20211206202811803-2114059589.jpg)
三、多态与多态性
class Animal: # 同一类事物:动物
def talk(self):
pass
class Dog(Animal): # 动物的形态之一:狗
def talk(self):
print("汪汪汪")
class Cat(Animal): # 动物的形态之二:猫
def talk(self):
print('喵喵!')
class Pig(Animal): # 动物的形态之一:猪
def talk(self):
print("哼哼哼!")
# 实例化得到三个对象
obj1 = Dog()
obj2 = Cat()
obj3 = Pig()
# 父类的功能是用来统一子类的,定标准的,只要看父类功能就知道子类也有
-
多态性指的是可以在不用考虑对象具体类型的情况下而直接使用对象,这就需要在设计时,把对象的使用方法统一成一种:例如obj1、obj2、obj3都是动物,但凡是动物肯定有talk方法,于是我们可以不用考虑它们三者的具体是什么类型的动物,而直接使用
obj1.talk()
# 汪汪汪
obj2.talk()
# 喵喵!
obj3.talk()
# 哼哼哼!
-
在多态性背景下用的继承,父类的功能其实不是真的拿来给子类用的,而是用来给子类定标准的,用来统一子类的,只需要把父类的功能规定好了,子类就肯定有,这样的好处是只要看父类就知道子类有什么功能
1.更进一步,我们可以定义一个统一的接口来使用
def talk(animal): # 定义一个函数talk 传进来参数就叫动物
animal.talk() # 只要是动物就肯定有talk方法
# 三个对象统一用一个函数talk去调,用起来统一了
talk(obj1)
talk(obj2)
talk(obj3)
综上我们得知,多态性的本质在于不同的类中定义有相同的方法名,这样我们就可以不考虑类而统一用一种方式去使用对象,可以通过在父类引入抽象类的概念来硬性限制子类必须有某些方法名
import abc
# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
def talk(self): # 抽象方法中无需实现具体的功能
pass
class Dog(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
def talk(self):
print("汪汪汪")
class Cat(Animal):
def talk(self):
print('喵喵!')
class Pig(Animal):
def tell(self): # 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化
print("哼哼哼!")
obj1 = Dog()
obj2 = Cat()
obj3 = Pig()
obj1.talk()
obj2.talk()
obj3.talk()
-
但其实我们完全可以不依赖于继承,只需要制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象,这正是Python崇尚的“鸭子类型”(duck typing):“如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子”。比起继承的方式,鸭子类型在某种程度上实现了程序的松耦合度,如下
# 三者看起来都像,三者都有talk功能,然而它们并没有直接的关系,且互相独立
class Dog:
def talk(self):
print("汪汪汪")
class Cat:
def talk(self):
print('喵喵!')
class Pig:
def talk(self):
print("哼哼哼!")
![image](https://img2020.cnblogs.com/blog/2577469/202112/2577469-20211206202821362-519529214.jpg)