网站做分布式部署,红色大气网站模板,比格设计官网,潍坊百度网站排名本章正式开始之前#xff0c;先让我们回顾一下什么是 对象 #xff1f; 什么是 类 #xff1f; 小贝 喜欢 猫咪#xff0c;今年领养了一只名叫 Kitty 的 布偶猫。则下列哪项是 对象 呢#xff1f; A. 猫咪 B. Kitty C. 布偶猫 相比之下#xff0c;闻闻 更喜欢 犬科 动…本章正式开始之前先让我们回顾一下什么是 对象 什么是 类 小贝 喜欢 猫咪今年领养了一只名叫 Kitty 的 布偶猫。则下列哪项是 对象 呢 A. 猫咪 B. Kitty C. 布偶猫 相比之下闻闻 更喜欢 犬科 动物家里养了两只 萨摩耶犬一只名叫 丁丁另一只名叫 当当。则下列哪项是 类 呢 A. 犬科 B. 萨摩耶犬 C. 丁丁 D. 当当 这两道题目中出现了 小贝 和 闻闻 这两位具体的人提到了 Kitty、丁丁、当当 这三只具体的动物他们都是 对象。这其中的人Human、猫咪Cat、布偶猫Dagdoll、萨摩耶Samoyed、犬科Dog几个 抽象概念 则是 类。 梳理清楚 类与对象 的关系后我们能快速定义出这几个类由类实例化出万千对象
# 人类
class Human: pass
# 猫咪
class Cat: pass
# 布偶猫
class Dagdoll: pass
# 狗狗
class Dog: pass
# 萨摩耶犬
class Samoyed: passxiaobei Human() # 小贝是人类
wenwen Human() # 闻闻是人类
kitty Dagdoll() # Kitty 是布偶猫
dingding Samoyed() # 丁丁是萨摩耶犬
dangdang Samoyed() # 当当是萨摩耶犬 拓展上述 Human 类、Cat 类、Dagdoll 类、Dog 类和 Samoyed 类中都只包含一条 pass 语句此时 pass 语句可以直接跟在 class xxx: 之后写成一行。 假如我们使用 Python 内置函数 isinstance() 询问“Kitty 是一只布偶猫吗”Python 会回答“是”。就像这样
print(Kitty 是一只布偶猫吗)
print(isinstance(kitty, Dagdoll))
# 输出
# Kitty 是一只布偶猫吗
# True
isinstance() 函数接受两个参数第一个参数为某个实例对象第二个参数为某个类能够检查第一个参数是否是第二个参数的 实例并返回 True 或 False。因此上述代码第 2 行中的 isinstance(kitty, Dagdoll) 是在检查 kitty 实例对象是否是 Dagdoll 的实例。答案显然易见是 True。这也符合常识——Kitty 当然是一只布偶猫。
同样的道理我们还可以检查丁丁、当当是否是萨摩耶犬。 ⚠️⚠️⚠️ 重点 ⚠️⚠️⚠️ 先定义 xiaobei Human() 再询问 isinstance(xiaobei, Human) 可按照现实中的逻辑我们知道 丁丁、当当是萨摩耶犬又知道 萨摩耶犬是犬科动物那么能顺理成章地推断出 丁丁、当当都是犬科动物。而如果我们询问 Python“丁丁是一条狗吗”此时 Python 却会回答“不是”。这就不太符合我们的预期了
# 丁丁是一只萨摩耶犬
dingding Samoyed()
print(丁丁是一只萨摩耶犬吗)
print(isinstance(dingding, Samoyed))
print(丁丁是一只狗吗)
print(isinstance(dingding, Dog))# 输出
# 丁丁是一只萨摩耶犬吗
# True
# 丁丁是一只狗吗
# False
️ 那我们该如何让 Python 知道 萨摩耶犬是犬科动物 这层关系呢
这就是我们接下来要学习的重点内容——类的继承。
继承
继承的语法
“继承”这个词我们并不陌生。例如张三 继承 了祖宅李四 继承 革命先烈遗志继承 这个词的本意指的是后辈从先辈承受、接受了某种物质或精神蕴含着一种 先与后、父与子的关系。放在计算机世界也一样类的继承规定了类的父子关系。
假如我们已经定义了 Dog 类想再定义一个它的 子类名叫 Samoyed那么可以写成这样
# 狗狗
class Dog: pass# 萨摩耶犬
class Samoyed(Dog): pass
注意看代码第 5 行老师定义 Samoyed 类时在类名后添加了一对圆括号并在圆括号内填入了 Dog 类的类名。这是在告诉 Python“我接下来定义的 Samoyed 类 继承自 Dog 类是它的 子类 哦。”
我们再检查一下“丁丁是否是狗”会发生什么呢
# 狗狗
class Dog: pass# 萨摩耶犬
class Samoyed(Dog): pass# 丁丁是一只萨摩耶犬
dingding Samoyed()
print(丁丁是一只狗吗)
print(isinstance(dingding, Dog))# 输出
# 丁丁是一只狗吗
# True 现在我们已经建立起 Samoyed 类和 Dog 类的关系让 Python 明白 萨摩耶是犬科动物 啦
并且就像我们现实中的逻辑假如我们只知道 丁丁是一只狗那么是无法确定 丁丁是否是萨摩耶品种 的所以当我们由 Dog 类实例化出实例对象 dingding再用 isinstance() 函数检查 dingding 是否是 Samoyed 类的实例会发现 Python 坦诚地回答“不是”
# 狗狗
class Dog: pass# 萨摩耶犬
class Samoyed(Dog): pass# 丁丁是一只狗
dingding Dog()
print(丁丁是一只萨摩耶犬吗)
print(isinstance(dingding, Samoyed))# 输出
# 丁丁是一只萨摩耶犬吗
# False
这就是 继承 的第一个好处。它能够让 Python 理解概念类与概念之间的范围关系父类与子类。
我们将刚刚定义的这些类放在一起可以很清晰地观察到类与类之间的关系
# 人类
class Human: pass# 猫咪
class Cat: pass
# 布偶猫
class Dagdoll(Cat): pass# 狗狗
class Dog: pass
# 萨摩耶犬
class Samoyed(Dog): pass
Dagdoll 类 继承 自 Cat 类反过来说Cat 类 派生 出了 Dagdoll 类。因此 Dagdoll 类是 Cat 类的子类Cat 类是 Dagdoll 类的父类。 单选题 仿照上面的说法我们知道Samoyed 类 ① 自 Dog 类反过来说Dog 类 ② 出了 Samoyed 类。 A① 继承② 派生 B① 派生② 继承 当然这题是选A的因为
在这些叫法中“父”与“子”是一对相对的概念通常一起出现比如 A 是 B 的父类B 是 A 的子类“继承”与“派生”也是一对相对的概念也会一起出现比如 A 继承自 BB 派生出 A。如果脱离语境去说“A 是父类”是 没有意义 的这点千万要注意啦。 继承 的第二个好处是当我们约定 A 类继承自 B 类后子类 A 将 自动获得 B 类中定义的 所有属性与方法。
子类调用父类方法
例如我们知道犬科动物有四条腿、能奔跑开心的时候会摇尾巴那么可以将 Dog 类扩充成如下形式
# 狗狗
class Dog:# 犬科动物有四条腿leg_num 4# 能奔跑def run(self):print( 狗狗快跑)# 开心的时候会摇尾巴def happy(self):print( 狗狗开心地摇起了尾巴)
此时我们再由 Dog 类派生出 Samoyed 类、Corgi 类柯基犬它们会自动地继承父类 Dog 中。因此由 Samoyed 类、Corgi 类实例化出的实例对象可以调用 run() 方法奔跑调用 happy() 方法快乐地摇尾巴
# 萨摩耶犬
class Samoyed(Dog): pass# 柯基犬
class Corgi(Dog): pass# 丁丁是一只萨摩耶犬
dingding Samoyed()
print(丁丁, end ) # 输出“丁丁”后不换行
# 丁丁能奔跑
dingding.run()# 小可是一只柯基犬
xiaoke Corgi()
print(小可, end )
# 小可在快乐地摇尾巴
xiaoke.happy()# 输出
# 丁丁 狗狗快跑
# 小可 狗狗开心地摇起了尾巴
Python 在执行到 dingding.run() 时会先检查 dingding 自身类型 Samoyed 中有没有 run() 方法发现没有再去 Samoyed 的父类 Dog 中寻找 run() 方法。这时它找到了 run() 方法知道自己需要输出一行字便把“ 狗狗快跑”打印到了屏幕上 ️ 既然 Python 会先检查自身类型中有没有对应方法那如果我们在 Dog 的子类 Samoyed 中 重新编写 run() 方法后再调用 dingding.run()比如
# 萨摩耶犬
class Samoyed(Dog):# 重新编写父类中定义的 run() 方法def run(self):# 该方法会输出 萨摩耶狂奔print( 萨摩耶狂奔)# 丁丁是一只萨摩耶犬
dingding Samoyed()
print(丁丁, end )
# 丁丁在奔跑
dingding.run()
请你按照要求和注释中的提示定义 Samoyed 类并实例化出 dingding 实例对象让 dingding 调用 run() 方法观察运行结果。 要求 Samoyed 类继承自 Dog 类在 Samoyed 类中编写 run() 方法该方法会输出 萨摩耶狂奔。 # 狗狗
class Dog:# 犬科动物有四条腿leg_num 4# 能奔跑def run(self):print( 狗狗快跑)# 开心的时候会摇尾巴def happy(self):print( 狗狗开心地摇起了尾巴)# 请在下方定义 Samoyed 类
class Samoyed(Dog):# 请在重新编写父类中定义的 run() 方法def run(self):# 该方法会输出 萨摩耶狂奔print(萨摩耶狂奔)# 实例化 Samoyed 类将生成的实例对象赋值给 dingding
dingding Samoyed()
print(丁丁, end )
# dingding 调用 run() 方法
dingding.run()# 输出
# 丁丁萨摩耶狂奔由此可以得出
Python 运行到 dingding.run() 时它依然会先到自身类型 Samoyed 中寻找。这时它发现Samoyed 类中有一个名叫 run() 的方法于是会直接执行该方法最终在屏幕上打印出“ 萨摩耶狂奔”。 Dog 类与它派生出的子类 Samoyed 中 都有名叫 run() 的方法但 Dog 类中的方法会打印“ 狗狗快跑”Samoyed 类中的方法则会打印“ 萨摩耶狂奔”。两个方法虽然名字相同实际完成的任务却不相同。这种现象被称为 多态。 下一章python的 多态