目录
第一种:from abc import ABCMeta,abstractmethod
(1) 如果一个子类继承的多个父类中有相同的方法,子类该如何继承父类的方法呢?
一、继承的概念
让类和类之间产生父子关系,让子类可以拥有父类的属性和方法,但不能继承私有属性
继承就是可以获取另一个类中的静态属性和普通方法
1,继承的作用:
提高代码的重用率
2,继承的格式
class 子类名(父类名):
.....代码....
.....代码.....
所有的类都默认继承object类
类 | 描述 | 举例 |
新式类(主要使用) | 把默认继承的object类写出来 | class Animal(object): |
旧式类 | 不用把默认继承的object类写出来 | class Animal(object): |
二、方法的复写以及使用
1,子类定义了和父类相同的方法
2,复写的条件:
当父类的方法不满足子类的需求的时候,就使用方法的复写
3,调用方法的顺序
先去子类里面找,找不到再去父类,父类里面找不到就报错
class Animal(object):
type = '动物'
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print('吃...')
def sleep(self):
print('睡觉...')
class Dog(Animal):
def eat(self):
print('吃狗粮...')
def look_door(self):
print('看大门...')
class Cat(Animal):
def eat(self):
print('吃小鱼...')
def climb(self):
print('爬树...')
dog = Dog('京东狗', 8)
dog.eat() # 吃狗粮...
dog.sleep() # 睡觉...
dog.look_door() # 看大门...
cat = Cat('天猫', 10)
cat.eat() # 吃小鱼...
cat.sleep() # 睡觉...
cat.climb() # 爬树...
4,super() 方法
当子类和父类有相同的方法的时候,子类默认调用自己的方法,不能使用父类的方法。
如果想要使用父类的方法,我们就可以用super() 方法来调用父类的方法
子类内部用 | 外部用 |
super().方法() | |
super(子类名,self).方法() | super(子类名.子类对象名).方法() |
父类名.方法(self) | 父类名.方法(子类对象名) |
class Animal(object):
type = '动物'
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
print('吃')
def sleep(self):
print('睡觉...')
class Dog(Animal):
def look_door(self):
print('看大门...')
def eat(self):
super().eat() # 调用父类的eat()方法
super(Dog, self).eat() # super(子类名,self).方法()
Animal.eat(self) # 父类名.方法(self)
print('吃狗粮...')
dog = Dog('京东狗', 8)
super(Dog, dog).eat() # super(子类名,子类对象名).方法()
Animal.eat(dog) # 父类名.方法(子类对象名)
dog.eat()
5, __init__() 方法
(1).如果子类不复写 __init__() 方法,就会自动调用父类的 __init__() 方法
(2).如果子类复写了 __init__() 方法,不会调用父类的 __init__() 方法, 但是不推荐这样使用
往后面直接添加 super().__init__() 方法就行
class Person(object):
def __init__(self, name):
self.name = name
print('Perosn...')
class Student(Person):
def __init__(self): # 没有调用父类的__init__方法,就没有参数name传进来,会存在隐患,计算机会报错
print('student...')
def test(self):
print(self.name) # 没有参数name传进来,该语句无法执行
student = Student('zs')
student.test()
class Person(object):
def __init__(self):
print('Person...')
class Student(Person):
def __init__(self):
super().__init__() # 调用父类的__init__()方法
print('student...')
student = Student()
# Person...
# student...
三、派生属性 / 属性的覆盖
子类也可以添加自己新的属性,或者在自己这里定义这些属性(不会影响父类)
子类和父类有相同的属性时,将调用子类自己的属性。
class Person(object):
num = 10
def __init__(self, name):
print('person...')
class Student(Person):
num = 20
def __init__(self, name, age): # age是派生属性
self.name = name
self.age = age
super().__init__(name) # 调用父类的__init__()方法
print('student...')
def eat(self):
print(super().num) # 调用父类的num值
print('xxxx')
student = Student('zs', 10) # 创建对象时,调用自己的__init__()方法
student.eat()
print(student.num)
# person...
# student...
# 10
# xxxx
# 20
四,私有方法和私有属性在继承中的体现
父类中的私有方法和私有属性时不能被子类继承下来的
class Person(object):
num = 10
__num1 = 20 # 私有属性
def __test1(self): # 私有方法
print('...test1...')
def test2(self):
print('Person test2')
class Student(Person):
def test(self):
Person.test2(self)
print(Student.num)
print('xxxx')
# print(Person.__num1) # 私有属性不能被继承下来
def test3(self):
print('test3')
self.test()
self.test2()
# self.__test1() # 私有方法能不能被继承下来
student = Student()
student.test()
student.test2()
student.test3()
# Person test2
# 10
# xxxx
# Person test2
# test3
# Person test2
# 10
# xxxx
# Person test2
五、抽象类
1,抽象类概述:
每个动物的吃,睡的状态都不一样,所以要在子类中复写这些方法,这样,父类中的方法就没用了,但不能把父类中的这些方法直接给删了,会报错,因此在这些方法中写个pass占位就不会报错了
如果子类继承父类的属性和方法,在子类中必须复写父类所有的属性和方法,否则会报错
抽象类中除了可以写抽象方法,还可以写普通方法
2,格式:
第一种:from abc import ABCMeta,abstractmethod
from abc import ABCMeta,abstractmethod
class 父类名(metaclass=ABCMeta):
@abstractmethod
def 方法(self):pass
from abc import ABCMeta, abstractmethod
class Animal(metaclass=ABCMeta):
@abstractmethod
def eat(self):
pass
@abstractmethod
def sleep(self):
pass
def play(self):
print('转悠...')
class Dog(Animal):
def eat(self):
print('吃狗粮...')
def sleep(self):
print('轻轻地睡觉...轻轻的看门')
dog = Dog()
dog.eat()
dog.sleep()
第二种:import abc
port abc
class 父类名(metaclass=abc.ABCMeta):
@abc.abstractmethod
def 方法名(self):pass
import abc
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def eat(self): pass
@abc.abstractmethod
def sleep(self): pass
def play(self):
print('转悠...')
class Dog(Animal):
def eat(self):
print('吃狗粮...')
def sleep(self):
print('轻轻的睡觉,轻轻地看门...')
dog = Dog()
dog.eat()
dog.sleep()
六、多继承
1,概念
一个子类可以继承多个父类,并且拥有多个父类所有的属性和方法
2,注意事项:
(1) 如果一个子类继承的多个父类中有相同的方法,子类该如何继承父类的方法呢?
使用 类名.mro()方法
类名.__mro__()方法 来查看类的搜索路径
根据这个搜索路径来查找该继承谁的方法,一般情况是先写谁,就先调用谁
(2) 类的搜索路径的查找顺序:
- 子类先于父类被检查
- 多个父亲会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
class A(object):
num_1 = 10
def test1(self):
print('A test1')
def test2(self):
print('A test2')
class B(object):
def test1(self):
print('B test1')
def test4(self):
print('B test4')
class C(B, A):
def test5(self):
print('C test5')
def test6(self):
print('C test6')
c = C()
c.test1() # B test1
print(C.mro()) # [<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
print(C.__mro__) # (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
c.test2() # A test2
c.test4() # B test4
c.test5() # C test5
c.test6() # C test6
七、继承原理 / 钻石原理
只有在Python3中才有mro() __mro__()方法
来查找类的搜索路径
八、多继承中的 super() 本质
super().方法名()
在每个类中调用test方法,沿着搜索路径往里退
class A(object):
def test(self):
print('A test')
class B(A):
def test(self):
super().test()
print('B test')
class C(A):
def test(self):
super().test()
print('C test')
class D(B, C):
def test(self):
super().test()
print('D test')
d = D()
d.test()
print(D.mro())
print(D.__mro__)
# A test
# C test
# B test
# D test
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)