
本文通过代码实证揭示:实例方法支持真正的运行时多态(基于对象类型动态绑定),而静态方法虽可“重写”,但其调用不依赖 `self`,无法参与继承链上的动态分发;只有当静态方法被实例方法间接调用时,才可能表现出类级别的多态行为。
在面向对象编程中,多态性(Polymorphism)的核心在于“同一接口,不同实现,且由运行时对象的实际类型决定具体执行哪个版本”。这一特性在 Python 的实例方法中天然成立,但在静态方法中并不成立——尽管二者语法上均可被子类“重定义”,其底层绑定机制与行为语义却有根本区别。
✅ 实例方法:真正的运行时多态
实例方法通过 self 隐式接收调用者对象,Python 在调用时会根据 self 的实际运行时类型(而非声明类型)查找并执行对应的方法。这是动态绑定(dynamic dispatch)的典型体现:
class BaseClass:
def greet(self):
return f"Hello from {self.__class__.__name__}"
class DerivedClass(BaseClass):
def greet(self):
return f"Hi there! I'm {self.__class__.__name__}"
obj = DerivedClass()
print(obj.greet()) # 输出: "Hi there! I'm DerivedClass"即使将 obj 赋值给一个 BaseClass 类型的变量(Python 中无显式类型声明,但逻辑上可视为基类引用),只要实际对象是 DerivedClass 实例,greet() 就始终调用子类版本——这正是多态的实质。
❌ 静态方法:无动态绑定,仅是名称覆盖(Shadowing)
静态方法使用 @staticmethod 装饰,不接收 self 或 cls,与任何实例或类状态无关。它本质上是“寄居”在类命名空间中的普通函数。子类中同名静态方法不会覆盖父类行为,而是独立存在、按调用点显式解析:
立即学习“Python免费学习笔记(深入)”;
class BaseClass:
@staticmethod
def say():
return "Base says hi"
class DerivedClass(BaseClass):
@staticmethod
def say():
return "Derived says hello"
# 显式通过类名调用 → 各自返回自己的实现
print(BaseClass.say()) # "Base says hi"
print(DerivedClass.say()) # "Derived says hello"
# 通过实例调用 → 实际仍由类名隐式决定(非 `self` 类型)
b = BaseClass()
d = DerivedClass()
print(b.say()) # "Base says hi" —— 解析为 BaseClass.say
print(d.say()) # "Derived says hello" —— 解析为 DerivedClass.say⚠️ 注意:d.say() 看似“多态”,实则是 Python 在实例上调用静态方法时,自动回溯 d.__class__ 获取所属类,再查找该类下的 say。这不是基于继承链的虚函数调用,而是编译期/解析期就确定的静态绑定。你无法通过 BaseClass().say() 调用到 DerivedClass.say(),哪怕传入的是子类实例——因为 BaseClass() 的 __class__ 就是 BaseClass。
? 关键验证:让多态“暴露”在间接调用中
要真正凸显两者的差异,需构造一个父类中定义、但内部调用子类重定义成员的场景。此时,实例方法会因 self 的动态性而触发多态;静态方法则不会——除非你显式用 self.__class__.static_method() 手动触发类查找:
class BaseClass:
def instance_method(self):
return "Base instance"
@staticmethod
def static_method():
return "Base static"
# 关键对比:此方法在 Base 中定义,但内部调用其他方法
def template_pattern(self):
return f"[Instance] {self.instance_method()} | [Static] {self.static_method()}"
class DerivedClass(BaseClass):
def instance_method(self):
return "Derived instance"
@staticmethod
def static_method():
return "Derived static"
base = BaseClass()
derived = DerivedClass()
print(base.template_pattern())
# 输出: [Instance] Base instance | [Static] Base static
print(derived.template_pattern())
# 输出: [Instance] Derived instance | [Static] Base static ← 注意!static_method 仍是 Base 版本✅ self.instance_method() 正确调用了 DerivedClass.instance_method(多态生效)
❌ self.static_method() 仍调用 BaseClass.static_method(静态方法未多态)
? 原因:self.static_method() 等价于 BaseClass.static_method(),因为 template_pattern 定义在 BaseClass 中,其内部对 static_method 的引用在定义时已静态解析为 BaseClass.static_method。Python 不会在运行时根据 self 类型重新解析静态方法名。
若想让静态方法也“参与多态”,必须显式使用类动态查找:
def template_pattern(self):
# 强制按 self 的实际类查找静态方法
return f"[Instance] {self.instance_method()} | [Static] {self.__class__.static_method()}"此时 derived.template_pattern() 将输出 "Derived static"——但这已不是语言原生多态,而是手动模拟。
✅ 总结:一句话区分
| 特性 | 实例方法 | 静态方法 |
|---|---|---|
| 是否参与多态 | ✅ 是(动态绑定,由 self 运行时类型决定) | ❌ 否(静态绑定,由定义位置或显式类名决定) |
| 调用依据 | self 的实际类型(如 DerivedClass 实例调用父类方法,仍走子类重写) | 方法被引用时的词法作用域类(即定义它的类,或显式调用的类) |
| 设计意图 | 操作实例状态,支持继承与多态 | 工具函数,逻辑与类/实例无关,仅借类命名空间组织 |
因此,判断一个方法是否真正具备多态性,不要看它能否被重写,而要看:当通过父类定义的方法间接调用它时,行为是否随实际对象类型自动改变。实例方法可以,静态方法不可以——这才是多态的本质检验标准。








