Python无需虚函数,因方法调用天然动态绑定;需用abc.ABC定义抽象方法强制子类实现;依赖命名一致性实现多态,建议配合mypy和Protocol进行静态检查。

Python里没有虚函数,但有更直接的实现方式
Python压根不提供虚函数这种语法糖,也不需要。它的方法调用天生就是动态绑定的——只要子类重写了父类方法,obj.method() 就自动走子类版本。这比C++的virtual + override更轻量,也更容易出错(比如拼错方法名就静默调用父类实现)。
真正要关注的不是“怎么模拟”,而是“怎么确保多态行为按预期发生”。常见陷阱包括:忘记self参数、方法签名不一致、误用@staticmethod或@classmethod导致绑定失效。
用abc.ABC强制子类实现特定方法
如果你需要类似C++纯虚函数(即父类不提供实现,子类必须重写),就用抽象基类。这不是可选项,是明确契约——没实现就实例化会直接报TypeError: Can't instantiate abstract class。
from abc import ABC, abstractmethod <p>class Shape(ABC): @abstractmethod def area(self) -> float: pass</p><p>class Circle(Shape): def <strong>init</strong>(self, r): self.r = r def area(self) -> float: # 必须实现,否则Circle无法实例化 return 3.14 * self.r ** 2
-
@abstractmethod只能修饰实例方法;若修饰@staticmethod,子类仍需用@staticmethod重写才生效 - 抽象方法可以有默认实现,但
@abstractmethod本身不阻止你写函数体——只是子类仍需显式覆盖才能实例化 - 检查是否为抽象类:用
isinstance(obj, ABC)不行,得用issubclass(cls, ABC)或hasattr(cls, '__abstractmethods__')
运行时检查方法是否存在,避免AttributeError
当不确定对象是否实现了某方法(比如处理第三方类或鸭子类型场景),别急着调用obj.draw(),先用hasattr()或getattr()兜底。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
立即学习“Python免费学习笔记(深入)”;
if hasattr(shape, 'render'):
shape.render()
else:
print(f"{type(shape).__name__} doesn't support render()")
-
hasattr(obj, 'method')内部会触发__getattribute__,可能引发副作用;更安全的是getattr(obj, 'method', None) is not None - 如果方法存在但抛异常(比如
NotImplementedError),hasattr仍返回True——它只管“有没有”,不管“能不能用” - 对性能敏感的循环中频繁调用
hasattr开销不小,可提前缓存结果:has_render = hasattr(obj, 'render')
用__subclasshook__让非继承类也能被识别为子类
标准库里很多协议(如Iterable)靠__subclasshook__实现“结构化匹配”。你可以自定义这个类方法,让某个没有显式继承Shape的类,在isinstance(x, Shape)时返回True。
class Shape(ABC):
@classmethod
def __subclasshook__(cls, subclass):
return hasattr(subclass, 'area') and callable(getattr(subclass, 'area'))
<p>class LegacyPolygon:
def area(self):
return self.width * self.height</p><h1>即使没继承Shape,isinstance也返回True</h1><p>assert isinstance(LegacyPolygon(), Shape)
-
__subclasshook__只影响isinstance()和issubclass(),不影响实际方法调用逻辑 - 返回
NotImplemented(不是False!)表示“我不确定,按常规继承关系判断” - 不要在
__subclasshook__里做耗时操作,它会在每次类型检查时执行
最常被忽略的点:Python的多态依赖命名一致性,而不是声明。拼错一个字母,运行时才暴露问题。与其花力气模拟C++机制,不如用mypy加类型注解+Protocol做静态检查,把错误拦在运行前。

















