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更明确。