0
点赞
收藏
分享

微信扫一扫

面向对象(Python):学习笔记之继承



文章目录


  • ​​1 单继承​​

  • ​​1.1 单继承的概念 语法和特点​​

  • ​​①. 单继承的概念​​
  • ​​②. 单继承的语法​​
  • ​​③. 几个专业术语​​
  • ​​④. 单继承的传递性​​

  • ​​1.2 方法的重写​​
  • ​​1.3 父类的私有属性和私有方法​​

  • ​​2 多继承​​

  • ​​2.1 多继承的概念 语法和特点​​

  • ​​① 多继承的概念​​
  • ​​②多继承的语法​​

  • ​​2.2 多继承的注意事项​​
  • ​​2.3 Python中的MRO-----方法搜索顺序​​
  • ​​2.4 新式类与旧氏(经典)类​​



继承


面向对象的三大特性:


  1. 封装:根据职责将属性和方法封装到一个抽象的类中
  2. 继承:继承实现代码的复用/重用,相同的代码不需要重复的编写
  3. 多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度

1 单继承

1.1 单继承的概念 语法和特点

①. 单继承的概念

子类拥有父类的所有的方法和属性

②. 单继承的语法

class 子类名(父类名):
pass

  • 子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
  • 子类中应该根据职责,封装子类中特有的属性和方法

首先让看一下 ​使用继承​ 和 ​不使用继承​ 的区别.

面向对象(Python):学习笔记之继承_父类

如果​不使用继承​,开发一个动物类与狗类,则代码如下:

class Animals:
def eat(self):
print("吃")
def drink(self):
print("喝")
def run(self):
print("跑")
def sleep(self):
print("睡")

class Dog:
def eat(self):
print("吃")
def drink(self):
print("喝")
def run(self):
print("跑")
def sleep(self):
print("睡")
def bark(self):
print("汪汪汪")

# 创建一个动物对象--狗对象
wangcai_1 = Animals()
wangcai_1.eat()
wangcai_1.drink()
wangcai_1.run()
wangcai_1.sleep()
wangcai_2 = Dog()
wangcai_2.eat()
wangcai_2.drink()
wangcai_2.run()
wangcai_2.sleep()
wangcai_2.bark()

运行结果:

面向对象(Python):学习笔记之继承_子类_02

在这里可以看到,Animales类和Dog类有着四个函数是相同的,如果不使用继承,代码会非常冗余.如果再开发一个哮天犬类呢,毫无疑问代码会非常长且多余.

并且如果动物喝水的方法需要修改,我们则需要修改每一个类中的喝水方法,这显然太过于繁琐.

如果使用继承:

class Animals:
def eat(self):
print("吃")

def drink(self):
print("喝")

def run(self):
print("跑")

def sleep(self):
print("睡")


class Dog(Animals):
def bark(self):
print("汪汪汪")


wangcai = Dog()
wangcai.eat()
wangcai.drink()
wangcai.run()
wangcai.sleep()
wangcai.bark()

运行结果:

面向对象(Python):学习笔记之继承_多继承_03

很显然,Dog子类继承了Animales的所有属性和方法.

而使用继承后,代码显然间带了许多.

③. 几个专业术语


  • Dog类是Animal类的​子类​,Animal是Dog的​父类​,Dog类是Animal类​继承
  • Dog类是Animal类的​派生类​,Animal类是Dog的​基类​,Dog类是Animal类​派生

④. 单继承的传递性


  • C类从B类继承,B类又从A类继承
  • 则C类具有B类和A类的所有属性和方法

即:子类拥有父类以及父类的父类中封装的所有属性和方法

class Animals:
def eat(self):
print("吃")

def drink(self):
print("喝")

def run(self):
print("跑")

def sleep(self):
print("睡")


class Dog(Animals):
def bark(self):
print("汪汪汪")


class XiaoTianQuan(Dog):
def fly(self):
print("我飞了")

xtq = XiaoTianQuan()
xtq.eat()
xtq.drink()
xtq.run()
xtq.sleep()
xtq.bark()
xtq.fly()

运行结果:

面向对象(Python):学习笔记之继承_父类_04

注意:子类只能继承自己的父类中的属性和方法,而不能继承和自己的父类从一个爷爷类中派生出来的类的方法.

即:XiaoTianQuan类不能继承Cat类中的方法

1.2 方法的重写


  • 子类拥有父类的所有属性和方法
  • 子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发.

方法的重写的应用场景:

  • 当父类的方法实现不能满足子类的需求时,可以对方法进行重写(Override)
    面向对象(Python):学习笔记之继承_多继承_05
    如果在子类中,对父类的方法进行了重写,则会执行子类中的方法而不执行父类中的方法.
    如图:
    面向对象(Python):学习笔记之继承_多继承_06

重写父类方法的两种情况:


  1. 覆盖父类的方法
    ①如果在开发中,父类的方法实现和子类的方法实现,完全不同
    ②就可以使用覆盖的方式,在子类中重新编写父类的方法实现
    具体的实现方式:就相当于在子类中定义了一个和父类同名的方法并实现
    重写之后,在运行的时候,只会调用子类中重写的方法,而不会调用父类中封装的方法
  2. 对父类方法进行扩展
    ①如果在开发中,子类的方法实现中包含父类的方法实现,即父类中原本封装的方法实现是子类方法的一部分.
    ②就可以使用扩展的方式
    Ⅰ.在子类中​重写​父类的方法
    Ⅱ.在需要的位置使用​super().父类方法​来调用父类方法的执行
    Ⅲ.代码其他的位置针对子类的需求,编写子类特有的代码实现

关于super


  • 在python中,super是一个特殊的类
  • super()就是使用super类创建出来的对象
  • 最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现

除此之外,调用父类名还有另外一种方式(Not important)

在Python 2.x的时候,如果需要调用父类的方法,可以使用以下方式


  • 父类名.方法(self)
  • 不推荐使用,因为一旦父类发生变化,方法调用位置的类名同样需要进行修改.

提示:


  • 在开发时,父类名 和 super()两种方式不要混用
  • 如果使用当前子类名调用方法,会形成递归调用,出现死循环

class Animals:
pass


class Dog(Animals):
def bark(self):
print("汪汪汪")


class XiaoTianQuan(Dog):
def fly(self):
print("我飞了")

def bark(self):
# 1.针对子类特有的需求,编写代码
print("我不想汪汪汪")
# 2.保留父类的方法
super().bark()
# 使用 父类名.方法(self)
# Dog.bark(self)
# 3.增加其他子类代码
print("123123")


xtq = XiaoTianQuan()
xtq.bark()

运行结果:

面向对象(Python):学习笔记之继承_子类_07

即:

如果向保留父类中的方法,首先要重写该方法,然后使用super().父类方法对其进行保留(调用),然后可以看情况增加后续代码.即​实现了我们在原有父类方法上进行扩充的目的​.

1.3 父类的私有属性和私有方法



子类对象不能再自己的方法内部,直接访问父类的私有方法或者私有属性



子类对象可以通过父类的公有方法间接访问到私有属性或私有方法
①私有属性、方法 是 对象的隐私,不对外公开,外界以及子类都不能直接访问
②私有属性、方法 通常用于做一些内部的事情
示例:
面向对象(Python):学习笔记之继承_多继承_08



B 的对象不能直接访问_num2属性



B 的对象不能在demo方法内访问_num2属性



B 的对象可以在demo方法内,调用父类的test方法



父类的test方法内部,能够访问_num2属性和_test方法



class A:
def __init__(self):
self.num1 = 100
self._num2 = 200
def _test(self):
print("私有方法 %d %d" % (self.num1, self._num2))
def test(self):
print("父类的公有方法")
self._test()
print("私有属性 %d" % self._num2)
class B(A):
def demo(self):
print("%d" % self.num1)
self.test()
b = B();
print(b)
b.demo()

运行结果:

面向对象(Python):学习笔记之继承_多继承_09

2 多继承

2.1 多继承的概念 语法和特点

① 多继承的概念


  • 子类可以拥有多个父类,并且具有所有父类的属性和方法
  • 例如:孩子会继承自己父亲和母亲的特征
    面向对象(Python):学习笔记之继承_多继承_10

②多继承的语法

class 子类名(父类名1,父类名2....):
pass
class A:
def test(self):
print("test 方法")


class B:
def demo(self):
print("demo 方法")


class C(A, B):
"""多继承可以让子类对象
同时具有多个父类的属性和方法"""
pass


# 创建子类对象
c = C()
c.test()
c.demo()

运行结果:

面向对象(Python):学习笔记之继承_多继承_11

2.2 多继承的注意事项

Question:

如果不同的父类中存在同名的方法,子类对象在调用时候,会调用哪一个父类中的方法呢?

提示:开发时,应该尽量避免这种容易产生混淆的情况!如果父类之间存在同名的属性或者方法,应该尽量避免使用多继承.

面向对象(Python):学习笔记之继承_多继承_12

这种情况下,在底层代码设计中,会针对不同情况进行不同选择.

比如针对继承循序:

面向对象(Python):学习笔记之继承_父类_13

当然,不止有这一种选择方式.

2.3 Python中的MRO-----方法搜索顺序

(仅供科普,不推荐使用重名多继承调用)


  • python中针对类提供了一个内置属性__mro__可以查看方法搜索顺序
  • MRO是 method resolution order,主要用于在多继承时判断方法,属性的调用
    面向对象(Python):学习笔记之继承_父类_14
  • 在搜索方法时,是按照__mro__的输出结果从左至右的顺序查找到
  • 如果在当前类中找到方法,就继续执行,不在搜索
  • 如果没有找到,就查找下一个类中是否有对应的方法,如果找到,就直接执行,不在搜索
  • 如果找到最后一个类,还没有找到方法,程序报错

2.4 新式类与旧氏(经典)类

object​是python中为所有对象提供的基类,提供一些内置的属性和方法,可以调用dir函数进行查看


  • 新式类:以object为基类的类,推荐使用
  • 经典类:不以object为基类的类,不推荐使用
  • 在Python 3.x中,定义类时,如果没有指定父类,会默认使用object作为该类的基类–Python 3.x中定义的类都是新式类
  • 在Python 2.x中,定义类时,如果没有指定父类,则不会使用object作为基类

新式类和经典类在使用多继承的时候,会影响到方法的搜索顺序

为了保证编写的代码能够同时在Python 2.x和Python 3.x中运行

在定义类的时候,如果没有父类,建议统一继承自 ​object

class 类名(object):
pass



举报

相关推荐

0 条评论