Python中方法重写为何不影响基类实例?
Python中方法重写为何不影响基类实例?
这问题问得太戳人了——刚摸Python面向对象的时候,我也盯着类似的例子挠头:为啥子类改了方法,父类实例完全不受影响?咱们结合你给的代码,一步步把底层逻辑说透~
先把你的示例代码贴出来方便对照:
class Animal: def speak(self): return "Animal speaks" class Dog(Animal): def speak(self): return "Dog barks" a = Animal() d = Dog() print(a.speak()) # 输出: Animal speaks print(d.speak()) # 输出: Dog barks
核心原因:每个类都是独立的「命名空间」
你猜的没错——Python里每个类都有自己独立的命名空间,方法、属性这些都是存在各自类的命名空间里的。
- 当你定义
Animal类时,speak方法是存在于Animal类的命名空间里的,相当于给Animal这个“大盒子”里放了一个叫speak的工具。 - 当你定义
Dog(Animal)时,它会先继承Animal里的所有工具,包括speak。但你紧接着在Dog里又定义了一个speak,这相当于在Dog自己的“盒子”里放了一个同名的新工具,把继承来的那个工具给覆盖了,但完全没碰Animal盒子里的原版工具。
实例调用方法时的查找逻辑
当你调用实例的方法(比如a.speak()),Python的查找路径是这样的:
- 先看实例自身有没有绑定这个方法(一般只有动态给实例加方法时才会有);
- 如果没有,就去实例所属的类的命名空间里找;
- 如果类里也没有,就顺着MRO(方法解析顺序)往上找父类、祖父类……直到找到或者抛出错误。
所以在你的例子里:
a是Animal的实例,找speak时直接去Animal的命名空间拿,自然是原版的“Animal speaks”;d是Dog的实例,找speak时先去Dog的命名空间,发现有自己定义的版本,就直接用“Dog barks”,根本不会再去Animal里找。
再通俗点理解:重写是「子类自定义」,不是「修改父类」
这就像你从图书馆借了一本《动物行为手册》(父类Animal),里面写着“动物的叫声:通用发声”。你回家之后自己抄了一本(子类Dog),把“叫声”那页改成了“汪汪叫”——但图书馆里的原版书还是原样,别人借原版书看到的还是原来的内容,只有你自己抄的这本是修改后的。
面向对象的继承和重写本来就是这个设计逻辑:子类可以根据自己的需求定制行为,但绝对不能影响父类的原有行为,否则所有继承自这个父类的子类都会被意外修改,那代码的稳定性就彻底崩了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

