在 Python 中,继承和多态是面向对象编程的两个重要概念。它们允许你创建和组织代码以实现代码重用和灵活性。
继承是一种创建新类的机制,新类可以继承现有类的属性和方法。被继承的类称为父类或基类,而继承得到的新类称为子类或派生类。子类可以继承父类的属性和方法,并且可以添加自己的属性和方法。
多态是面向对象编程的另一个重要概念,它允许不同的对象对相同的方法做出不同的响应。简单来说,多态允许你使用父类的引用来引用子类对象,并根据实际对象类型的不同而执行不同的操作。
- 继承 {#title-0} ================
1.1 继承语法 {#title-1}
class Base:
def __init__(self):
self.base_a = 100
def base_function(self):
print('hello world')
# 如果子类没有添加 __init__ 方法,则会自动父类初始化方法
# 否则,就需要手动调用父类的 __init__ 方法
class Demo(Base):
def __init__(self):
super(Demo, self).__init__()
demo = Demo()
demo.base_function()
print(demo.base_a)
1.2 继承中同名函数 {#title-2}
class Base:
def __init__(self):
self.base_a = 100
def my_function(self):
print('base hello world')
# 如果子类没有添加 __init__ 方法,则会自动父类初始化方法
# 否则,就需要手动调用父类的 __init__ 方法
class Demo(Base):
def __init__(self):
super(Demo, self).__init__()
def my_function(self):
print('demo hello world')
demo = Demo()
# 子类与父类方法同名,优先调用子类的同名方法
demo.my_function()
# 特殊方法调用父类同名函数
Base.my_function(demo)
- 多态 {#title-3} ================
面向对象中的多态可以理解为一个对象具有多种形态或多种表现方式的能力。它允许我们使用同一种操作来处理不同类型的对象,而不需要在代码中显式地区分对象的具体类型。
# 对于 obj 参数而言,你传递什么 obj 就是什么,一个 obj 变量具有多种不同的形态
# 对于 do_logic 函数而言,我不管你传递什么类型,只要这个类型有 attack 函数就可以工作
def do_logic(obj):
obj.attack()
class WangSan:
def attack(self):
print('王三 attack')
class Zhaoliu:
def attack(self):
print('赵六 attack')
class Cat:
def attack(self):
print('小猫 attack')
class Dog:
def attack(self):
print('小狗 attack')
if __name__ == '__main__':
wangsan = WangSan()
zhaoliu = Zhaoliu()
xiaomao = Cat()
xiaogou = Dog()
# 同一个函数可以传递不同类型的变量
do_logic(wangsan)
do_logic(zhaoliu)
do_logic(xiaomao)
do_logic(xiaogou)
程序输出结果:
王三 attack
赵六 attack
小猫 attack
小狗 attack
由于 Python 变量本身就是动态类型,故而函数形参变量本身就支持多态,不需要像其他语言一样,必须有继承的支持。
2.1 继承在多态中的应用 {#title-4}
当我们设计 do_logic 函数时,我们希望只接受 Person 类型的王三、赵六等对象,而不希望接受动物类型的。我们可以使用 isinstance 来判断传入对象的类型,如下代码所示(do_logic 函数修改如下):
def do_logic(obj):
if not isinstance(obj, Zhaoliu) and not isinstance(obj, WangSan):
return
obj.attack()
如果 Person 类型太多的话,这个判断过程实在难写。所以,我们通过继承关系来简化(当子类继承父类,子类也是父类类型):
class Person():
def attack(self):
print('default attack')
class WangSan(Person):
def attack(self):
print('王三 attack')
class Zhaoliu(Person):
def attack(self):
print('赵六 attack')
class Cat:
def attack(self):
print('小猫 attack')
class Dog:
def attack(self):
print('小狗 attack')
def do_logic(obj):
assert isinstance(obj, Person)
obj.attack()
if __name__ == '__main__':
wangsan = WangSan()
zhaoliu = Zhaoliu()
xiaomao = Cat()
xiaogou = Dog()
# 同一个函数可以传递不同类型的变量
do_logic(wangsan)
do_logic(zhaoliu)
do_logic(xiaomao)
do_logic(xiaogou)
2.2 抽象基类 {#title-5}
我们大部分情况下,希望父类能够对子类的行为进行约束,即:约束子类必须重写某些方法,此时我们可以使用 abc 模块来实现,示例代码如下:
import abc
class Person(metaclass=abc.ABCMeta):
# 抽象方法,子类必须实现
@abc.abstractmethod
def attack(self):
pass
def other_action(self):
print('其他行为')
class WangSan(Person):
def attack(self):
print('王三 attack')
class Zhaoliu(Person):
pass
def do_logic(obj):
obj.attack()
if __name__ == '__main__':
wangsan = WangSan()
zhaoliu = Zhaoliu()
# 同一个函数可以传递不同类型的变量
do_logic(wangsan)
do_logic(zhaoliu)
上面代码中,类 Zhaoliu 并没有实现父类要求的 attack 方法,故而出现如下报错:
TypeError: Can't instantiate abstract class Zhaoliu with abstract methods attack