Skip to content

Python 多态(polymorphism)

多态指:同一套接口(如同一方法名、同一函数调用形式)作用于不同类型的对象时,可以表现出各自不同的行为。调用方往往只关心「有没有这个方法」,而不必写死具体类型。

在 Python 中,多态常与鸭子类型一起出现:不强制继承同一父类,只要对象实现了所需方法即可。与 OOP 总览见 面向对象编程;继承与方法重写见 类的继承多重继承;运算符侧见 运算符重载

鸭子类型:不同类,同一调用方式

下面 RabbitHorse 都有 age()color(),可以放在同一循环里调用,而无需判断类型:

python
class Rabbit:
    def age(self):
        print("计算兔子的年龄。")

    def color(self):
        print("计算兔子的颜色。")


class Horse:
    def age(self):
        print("计算马的年龄。")

    def color(self):
        print("计算马的颜色。")


obj1 = Rabbit()
obj2 = Horse()

for creature in (obj1, obj2):
    creature.age()
    creature.color()

注意:循环变量不要用 type,以免遮蔽内置函数 type()

输出:

text
计算兔子的年龄。
计算兔子的颜色。
计算马的年龄。
计算马的颜色。

继承与方法重写

子类定义与父类同名的方法会重写父类实现;通过父类引用统一接口调用时,实际执行的是对象真实类型上的方法,这是经典 OOP 多态。

python
class Animal:
    def kind(self):
        print("各种动物。")

    def age(self):
        print("动物的年龄(基类默认说明)。")


class Rabbit(Animal):
    def age(self):
        print("兔子的年龄。")


class Horse(Animal):
    def age(self):
        print("马的年龄。")


a = Animal()
r = Rabbit()
h = Horse()

a.kind()
a.age()

r.kind()
r.age()

h.kind()
h.age()

输出:

text
各种动物。
动物的年龄(基类默认说明)。
各种动物。
兔子的年龄。
各种动物。
马的年龄。

Rabbit / Horse 未重写 kind,故沿用 Animal.kindage 在子类中被重写,因此表现不同。

与「方法重载」的区别

Java 等语言里常见的编译期多态 / 方法重载(同名方法、不同参数列表)在 Python 中没有后定义的同名函数会覆盖先定义的;动态派发主要依据运行时对象类型(以及可选的 functools.singledispatch 等模式),而不是仅靠参数个数区分重载。

运算符多态

+* 等运算符对 intstrlist 等不同类型有不同含义;自定义类可通过 __add__ 等参与同一机制,见 运算符重载

小结

  • 多态:同一接口,不同实现;Python 中鸭子类型很普遍。
  • 继承 + 重写是典型子类型多态;运算符重载是另一种「同一符号,不同语义」。
  • Python 不以参数列表做方法重载;需要时分派可用 singledispatch 等方案。

参考