应使用@classmethod而非@staticmethod,因前者自动传入动态cls参数支持继承与子类覆盖,后者无隐式参数且硬编码类名导致扩展失效。

该用 @classmethod 的地方写成 @staticmethod,不会报错,但子类一继承就逻辑失效——这种 bug 往往上线后才暴露。
调用时第一个参数到底传什么?
Python 不会猜你想要什么,全靠装饰器决定隐式参数:
-
@classmethod方法必须带cls参数,Python 自动把「真正发起调用的那个类」塞进去。哪怕你是用SubClass().method()调的,cls也是SubClass,不是父类名,更不是硬编码的类名 -
@staticmethod方法没有隐式参数,self和cls都不会自动传;你写def parse(s),就真的只收一个s
能不能访问类属性或调用其他类方法?
这是最常踩坑的地方:
-
@classmethod可直接用cls.config、cls.count += 1、cls.create_from_json()——天然支持继承和子类覆盖 -
@staticmethod想访问类属性?只能硬写MyClass.config。类名一改,全挂;子类想换配置?做不到 - 常见误用:数据库连接工厂、JSON 反序列化构造器、策略分发入口——这些本该感知调用者类,却用
@staticmethod锁死了扩展性
子类继承时行为是否一致?
关键差异藏在 MRO 和动态绑定里:
-
@classmethod参与 MRO 查找,子类调用时cls是子类本身,子类可重写同名方法实现真正覆盖(overriding) -
@staticmethod不参与 MRO,子类同名方法只是遮蔽(shadowing),父类方法仍可被显式调用,且无法感知子类存在 - 如果这个函数未来可能需要根据子类切换行为(比如不同子类返回不同格式的 JSON),必须用
@classmethod
最容易被忽略的一点:cls 是动态的,它不等于定义时的类,而是等于「此刻真正发起调用的那个类」。这个动态性一旦被 @staticmethod 抹掉,子类就失去了一切可定制机会——而这种 bug 往往上线后才暴露。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











