继承(面向对象中核心)
# 接口 interface
# 继承就是一种新建类的方式, 新建出来的类我们称为是'子类或者叫派生类',被继承的类我 们称为是'父类或者是基类'
# 子类可以遗传父类的所有属性
# 类: 解决对象与对象之间的代码冗余问题
继承: 解决类与类之间的代码冗余问题
# 类: 经典类:没有继承object类的子子孙孙类都是经典类 A
新式类:继承了object类的子子孙孙类都是新式类 B
calss A():
pass
calss B(object):
pass
# 注意:1、只有在Python2中才区分经典类和新式类
2、Python3的版本都是新式类,默认的类都是继承了object类,不写也是 AB
class Parent1:
pass
class Parent2:
pass
class Sub(Parent1): # 单继承,Sub2是子类,Parent1是父类
pass
class Sub2(Parent1, Parent2): # 多继承
pass
# 其中:1、单继承:一个类只继承了一个类 # Sub
2、一个类继承了两个或者两个以上的类就是多继承了 # Sub2
# 查看继承了哪些类:类名.__bases__
print(Sub1.__bases__) # (<class '__main__.Parent1'>,)
"""继承的实际案例"""
class People(): # 属性查找,自己没有就去类里面找
school = 'SH' # 公共的地方
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Student(People):
def __init__(self, name, age, gender, course=None):
if course is None:
course = []
"""子类里面一定再次调用父类的__init__方法"""
People.__init__(self, name, age, gender) # 指名道姓的调用方法
self.course = course
def choose_course(self):
print('%s 选课成功, %s' % (self.name, self.course))
class Teacher(People):
def __init__(self, name, age, gender, level):
People.__init__(self, name, age, gender)
self.level = level
def score(self, stu_name):
print('%s 得了%s分' % (stu_name, 10))
stu = Student('ly', 20, 'male')
print(stu.school) # SH 属性的查找
print(stu.name)
print(stu.age)
print(stu.gender)
tea = Teacher('kevin', 19, 'female')
print(tea.name)
print(tea.age)
print(tea.gender)
单继承下的属性查找
# 单继承下的属性查找:先从对象自己名称空间中查找,然后去产生这个对象的类中查找, 最后去继承的父类中查找.
class Foo(A):
def f1(self):
print('from Foo.f1')
def f2(self):
print('from Foo.f2')
self.f1() # self,谁调用了就是谁是参数
class Bar(Foo):
def f1(self):
print('from Bar.f1')
obj = Bar()
obj.f2() # from Bar.f1
# 若__f1隐藏,在哪个类中隐藏,就会依据类变形,此时self.__f1已经定好
class Foo(A):
def __f1(self): # _Foo__f1
print('from Foo.f1')
def __f2(self):
print('from Foo.f2')
self.f1() # _Foo__f1 发生了变形,在哪个类里面就依据变形,已经定好
class Bar(Foo):
def __f1(self):
print('from Bar.f1')
obj = Bar()
obj.f2() # from Foo.f1
多继承下的属性查找
# 多继承下:菱形查找和非菱形查找
# 菱形:经典类:按照深度优先的查找顺序
新式类:按照广度优先查找
# 深度优先:第一条找到底,底找过后面就不找了
# 广度优先:最后一条线去G,前面不找G
X G-->X
# Python3 都是新式类,都是广度优先查询,也是就是最后才走到底
super和mro的使用
People.__init__(self, name, age, gender) # 指名道姓的调用方法
super(Student,self).__init__(name,age,gender) # Student是类名,依据而定
"""返回的是一个对象,并且是一个超级对象"""
以上两个是等价意思,但是People是没有父子关系,而super是绑定的
# super是python3中的写法,执行父类的,在python2中没有
print(A.mro()) # (<class '__main__.A'>, <class 'object'>)
print(A.__mro__)
# mro列表是通过一个C3算法得出来的,我们无需明白底层原理
# 在打印mro列表的时候,一定是从起始类开始
# 类要是多,用类.__mro__查找顺序
多态和鸭子类型
# 多态它是面向对象的三大特征之一
同一种事物的多种形态 # 动物:人、狗、猪、等都是动物的一种形态,都具备同一特征
# @abc.abstractmethod # 把抽象类中得方法变成抽象方法, 它不实现具体的功能,就是单 纯的为了限制子类中的方法
# 抽象类只能够被继承、不能够被实例化,会强制子类必须有某种方法
import abc # abstract class 抽象类 具体的Specific
class Animal(metaclass=abc.ABCMeta): # 把animal类变成了抽象类,括号内无值时是普通类
@abc.abstractmethod
def speak(self):
pass
@abc.abstractmethod
def jiao(self):
pass
"""Python崇尚的是鸭子类型"""
# 鸭子类型:更多的关注的是对象的行为,而不是对象的类型
# 多态带来的特性:在不考虑对象类型的情况下,直接调用对象的方法或者属性
class People(Animal):
def speak(self):
pass
class Dog(Animal):
def speak(self):
pass
class Pig(Animal):
def speak(self):
pass
obj = People() # 只要是动物就调,不管有没有speak
obj1 = Dog() # 是动物就有,不是动物就没有--》报错
obj2 = Pig()
def animal(obj):
return obj.speak()
animal(obj)
animal(obj1)
animal(obj2)
"""面试题:请举出Python中使用多态的例子:len"""
len('hello')
len([1,2,3,4])
len((1,2,3,4))
def len(obj):
return obj.__len__
len('helloworld')
len([1,2,3,4])
len((1,2,3,4))