Python多态指的是:同一套调用写法,作用在不同对象上可以走出不同行为。语言本身偏鸭子类型,不强制共享某个父类,只要对象提供了所需的方法,就能被同一段代码调用。

同名方法,不同结果

make_speak 只要求参数有 speak 方法,并不询问它到底是 Dog 还是 Cat。传入不同实例,打印内容不同:

class Dog:
    def speak(self):
        print("汪汪!")

class Cat:
    def speak(self):
        print("喵喵!")

def make_speak(animal):
    animal.speak()

make_speak(Dog())
make_speak(Cat())

鸭子类型

判定能不能用,看的是行为而不是名义上的血统。汽车、自行车、鸟彼此没有继承关系,但都实现了 move,就能交给同一个 go

class Car:
    def move(self):
        print("汽车在跑")

class Bike:
    def move(self):
        print("自行车在骑")

class Bird:
    def move(self):
        print("鸟在飞")

def go(vehicle):
    vehicle.move()

go(Car())
go(Bike())
go(Bird())

继承下的多态

需要一组对象遵守同一接口时,可以在父类里约定方法名,子类各自实现。父类里用 NotImplementedError 占位,能提醒子类必须提供自己的版本:

class Shape:
    def area(self):
        raise NotImplementedError("子类必须实现 area")

class Circle(Shape):
    def __init__(self, r):
        self.r = r
    def area(self):
        return 3.14 * self.r * self.r

class Square(Shape):
    def __init__(self, side):
        self.side = side
    def area(self):
        return self.side * self.side

shapes = [Circle(2), Square(3)]
for s in shapes:
    print(s.area())

内置函数里的多态

len 能作用于字符串、列表、元组,靠的是它们都实现了 __len__。自己的类只要提供同名特殊方法,也能接入这套调用:

print(len("hello"))
print(len([1, 2, 3]))
print(len((1, 2)))

class Team:
    def __init__(self, members):
        self.members = members
    def __len__(self):
        return len(self.members)

t = Team(["a", "b", "c"])
print(len(t))

需要时再用 isinstance

多数时候直接调用方法即可。若确实要按类型分支处理,可以用 isinstance。分支过多时,更值得回头检查是否该用统一的方法名消化差异:

def describe(x):
    if isinstance(x, int):
        return f"整数 {x}"
    elif isinstance(x, str):
        return f"字符串 '{x}'"
    else:
        return f"其他 {type(x).__name__}"

print(describe(5))
print(describe("hi"))

常见误区

  • 多态不一定依赖继承。鸭子类型下,同名方法就足够被同一段代码调用。
  • 传入缺少所需方法的对象会触发 AttributeError。若边界输入很杂,可先 hasattr 判断,或让调用方保证接口。
  • 父类里若写了空实现却不提醒,子类忘了重写时可能静默出错。需要强制子类实现时,用 NotImplementedError 更明确。