1. 简介
- 单继承:子类只继承一个父类
- 多层继承:继承关系为多层传递,如生活中的
爷爷、父亲、儿子
1.1 定义
1.1 生活中的继承
在现实生活中,继承一般指的是子女继承父辈的财产,如下图:
1.2 程序中的继承
在程序中,继承描述的是指的是类与类之间的关系,如下如所示:
- 站在父类的角度来看,父类派生出子类
- 站在子类的角度来看,子类继承于父类
- 父类也叫基类,子类也叫派生类
1.2 作用
- 继承:子类直接具备父类的能力(属性和方法)
- 作用:解决代码重用问题,提高开发效率
1.3 语法格式
继承的语法格式:
class 子类名(父类名):
pass
示例代码:
# 定义一个父类
class Father(object):
# 添加一个属性, money
def __init__(self):
self.money = 9999999
def print_info(self):
print(self.money)
# 定义一个子类,继承与Father
class Son(Father):
pass
# 子类创建对象
s = Son()
print(s.money) # 子类私用继承过来的属性
s.print_info() # 子类使用继承过来的方法
注意:
- 子类对象调用方法有一个就近原则
- 如果本类能找到方法,直接调用本类的方法
- 如果本类找不到,则调用父类继承过来的方法
2. 分类
2.1 单继承
- 单继承:子类只继承一个父类
# 定义一个父类, Animal
class Animal(object):
def eat(self):
print('吃东西')
# 定义一个子类,只有一个父类
class Dog(Animal):
pass
# 创建一个子类对象
dog1 = Dog()
dog1.eat()
2.2 多层继承
- 多层继承:继承关系为多层传递,如生活中的
爷爷、父亲、儿子
# 定义一个爷爷类, Animal
class Animal(object):
def eat(self):
print('吃东西')
# 定义一个父亲类
class Dog(Animal):
def drink(self):
print('喝东西')
# 定义一个儿子类
class SuperDog(Dog):
pass
# 创建对象
sd = SuperDog()
sd.eat()
sd.drink()
2.3 多继承
1. 简介
1.1 定义
- 所谓多继承,即子类有多个父类,并且具有它们的特征。
1.2 语法格式
class 子类名(父类1, 父类2, ……):
pass
示例代码:
# 定义2个类,它们没有继承关系,是平级的
class SmallDog(object):
def eat(self):
print('吃小东西')
# 再定义一个类
class BigDog(object):
def drink(self):
print('大口喝水')
# 定义一个子类,多继承于上面2个父类
class SuperDog(SmallDog, BigDog):
pass
# 定义子类对象,调用方法
sd = SuperDog()
sd.eat()
sd.drink()
运行结果:
吃小东西
大口喝水
2. 操作
2.1查看类的继承顺序
- 查看类的继承顺序:
类名.__mro__
示例代码:
# 定义2个类,它们没有继承关系,是平级的
class SmallDog(object):
def eat(self):
print('吃小东西')
# 再定义一个类
class BigDog(object):
def drink(self):
print('大口喝水')
# 定义一个子类,多继承于上面2个父类
class SuperDog(SmallDog, BigDog):
pass
# 查看类的继承顺序
print(SuperDog.__mro__)
运行结果:
(<class '__main__.SuperDog'>, <class '__main__.SmallDog'>, <class '__main__.BigDog'>, <class 'object'>)
2.2 调用父类同名方法
1. 默认调用情况
- 如果继承过来的2个父类的方法同名,默认调用先继承父类的同名方法
# 定义2个类,它们没有继承关系,是平级的
class SmallDog(object):
def eat(self):
print('吃小东西')
# 再定义一个类
class BigDog(object):
def eat(self):
print('啃大骨头')
# 定义一个子类,多继承于上面2个父类
class SuperDog(SmallDog, BigDog):
pass
# 定义子类对象,调用方法
sd = SuperDog()
sd.eat() # 默认先调用先继承的父类,即 SmallDog
运行结果:
吃小东西
2. 子类重写父类同名方法
- 父类的方法不能满足子类的需要,可以对父类的方法重写,重写父类方法的目的是为了给他扩展功能
- 在子类中定义了一个和父类同名的方法(参数也一样),即为对父类的方法重写
- 子类调用同名方法,默认只会调用子类的
示例代码:
# 定义一个父类, Animal
class Animal(object):
# 添加一个type属性
def __init__(self):
print('Animal类中的__init__')
self.type = '动物'
# 设计一个方法,打印属性
def print_type(self):
print('Animal类中的print_type = ', self.type)
# 定义一个子类,继承与Animal
class Dog(Animal):
# __init__和父类的同名,重写父类同名方法
def __init__(self):
print('Dog类中的__init__')
self.type = '可爱的小狗'
# print_type和父类的同名,重写父类同名方法
def print_type(self):
print('Dog类中的print_type = ', self.type)
# 定义一个子类对象
dog1 = Dog() # 调用子类的__init__
dog1.print_type() # 调用子类的print_type()
运行结果:
Dog类中的__init__
Dog类中的print_type = 可爱的小狗
3. 子类调用父类同名方法
- 子类调用父类同名方法:
父类名.同名方法(self, 形参1, ……)
:调用指定的父类super(类名, self).同名方法(形参1, ……)
:调用继承顺序中类名的下一个类的同名方法super().同名方法(形参1, ……)
:调用先继承父类的同名方法(是方法2的简写,比较推荐)
示例代码:
# 定义2个类,它们没有继承关系,是平级的
class SmallDog(object):
def eat(self):
print('吃小东西')
# 再定义一个类
class BigDog(object):
def eat(self):
print('啃大骨头')
# 定义一个子类,多继承于上面2个父类
class SuperDog(SmallDog, BigDog):
def eat(self):
print('吃蟠桃')
print('='*20)
# 子类调用父类同名方法:
# 1. 父类名.同名方法(self, 形参1, ……)
SmallDog.eat(self) # 调用SmallDog的eat()
print('=' * 20)
# 2. super(类名, self).同名方法(形参1, ……):调用继承顺序中类名的下一个类的同名方法
# 继承顺序中,SmallDog的下一个类是BigDog,所以,调用BigDog的eat()
super(SmallDog, self).eat()
print('=' * 20)
# 3. super().同名方法(形参1, ……) :调用先继承父类的同名方法
super().eat()
# 定义子类对象,调用方法
sd = SuperDog()
sd.eat()
运行结果:
吃蟠桃
====================
吃小东西
====================
啃大骨头
====================
吃小东西
示例代码:
# 定义一个父类, Animal
class Animal(object):
# 添加一个type属性
def __init__(self):
print('Animal类中的__init__')
self.type = '动物'
# 设计一个方法,打印属性
def print_type(self):
print('Animal类中的print_type = ', self.type)
# 定义一个子类,继承与Animal
class Dog(Animal):
# __init__和父类的同名,重写父类同名方法
def __init__(self):
print('Dog类中的__init__')
self.type = '可爱的小狗'
# print_type和父类的同名,重写父类同名方法
def print_type(self):
print('Dog类中的print_type = ', self.type)
print('='*20)
# 调用父类同名函数
# 方法1: 父类名.同名方法(self, 形参1, ……)
Animal.__init__(self)
Animal.print_type(self)
print('=' * 20)
# 方法2:super(子类名, self).同名方法(形参1, ……)
super(Dog, self).__init__()
super(Dog, self).print_type()
print('=' * 20)
# 方法3:super().同名方法(形参1, ……) # 是 4.2 方法的简写
# 推荐使用的方法
super().__init__()
super().print_type()
# 定义一个子类对象
dog1 = Dog() # 调用子类的__init__
dog1.print_type() # 调用子类的print_type()
运行结果:
Dog类中的__init__
Dog类中的print_type = 可爱的小狗
====================
Animal类中的__init__
Animal类中的print_type = 动物
====================
Animal类中的__init__
Animal类中的print_type = 动物
====================
Animal类中的__init__
Animal类中的print_type = 动物
3.私有和继承
3.1 权限
权限有属性权限和方法权限
1. 私有属性
- 如果在属性名前面加了2个下划线’__’,则表明该属性是私有属性,否则为公有属性
- 私有属性只能在类的内部访问
"""
私有属性:
1. __(2个下划线)开头的属性,就是私有属性
2. 只能在本类的内部访问,在类的外面无法直接访问
"""
class Dog(object):
# 添加属性
def __init__(self):
self.__baby_count = 0 # 私有属性,以__(2个下划线)开头的属性
self.age = 1 # 公有属性
def print_info(self):
print(self.__baby_count)
# 类的外部
# 创建对象
dog1 = Dog()
# print(dog1.__baby_count) # err, 私有属性,在类的外面无法直接访问
print(dog1.age)
dog1.print_info()
2. 私有方法
- 私有方法和私有属性类似,在方法名前面加了2个下划线’__’,则表明该方法是私有方法
- 私有方法只能在类内部使用
"""
私有方法:
1. __(2个下划线)开头的方法,就是私有方法
2. 只能在本类的内部访问,在类的外面无法直接访问
3. 在类的内部调用实例方法的语法格式:self.方法名()
"""
class Dog(object):
def __init__(self):
self.__baby_count = 0 # 私有属性,以__(2个下划线)开头的属性
self.age = 1
def print_info(self):
print(self.__baby_count)
self.__leave()
# 定义一个私有方法
def __leave(self):
print('休产假了')
dog1 = Dog()
dog1.print_info()
# AttributeError: 'Dog' object has no attribute '__leave'
# dog1.__leave() # err, 外部不能访问私有方法
3.2 关系
- 父类中的私有方法、属性不能直接继承使用
- 可以通过调用继承的父类的共有方法,间接的访问父类的私有方法、属性
# 定义一个父类, Animal
class Animal(object):
# 添加一个type属性
def __init__(self):
self.__type = '动物' # 私有
def __leave(self): # 私有
print('休产假3个月')
# 通过公有方法,间接访问私有元素
def use_private(self):
print(self.__type)
self.__leave()
# 定义一个子类
class Dog(Animal):
def test(self):
# print(self.__type) # err,私有不能直接继承使用
# self.__leave() # err,私有不能直接继承使用
pass
# 创建子类对象
dog1 = Dog()
dog1.use_private()