Python新手继承问题:继承是否仅创建指向基类对象的指针?
嘿,这个问题问得相当精准,正好触及了Python继承机制里一个容易被误解的细节!咱们一步步拆解清楚:
首先先还原你的代码和现象:
class A: def foo(self): print("a") class B(A): pass b = B() print(getattr(b, "foo")) # 输出:<bound method A.foo of <__main__.B object at 0x000000000604CC88>>
你看到输出里标注的是A.foo,就疑惑是不是继承只是创建指向基类对象的指针?答案是不是的,这背后是Python的「属性查找链」和「方法绑定机制」在共同作用。
为什么输出会显示A.foo?
当你通过实例b获取foo属性时,Python会按这个顺序查找:
- 先查
b自己的实例属性(也就是b.__dict__里的内容),没找到foo; - 接着查
B类的属性(B.__dict__),因为B继承自A但没重写foo,也没找到; - 最后沿着继承链查到
A类的属性,找到了定义在A里的foo函数。
这时候,Python会自动把这个普通函数包装成一个绑定方法——它会把实例b和A.foo函数绑定在一起,所以你看到的输出里会标注bound method A.foo,同时指明绑定的是B的实例。这个绑定方法的作用是:当你调用b.foo()时,它会自动把b作为self参数传给A.foo,不用手动传参。
继承不是简单的「指针指向基类」
子类并不会把基类的方法复制一份到自己的命名空间里,而是依靠**方法解析顺序(MRO)**来实现属性查找。每个类都有一个__mro__元组,比如B.__mro__的结果是(B, A, object),Python会严格按照这个顺序查找属性。
举个直观的例子,要是你给B添加自己的foo方法:
class B(A): def foo(self): print("b")
这时候再调用getattr(b, "foo"),输出就会变成<bound method B.foo of <__main__.B object at 0x...>>——因为查找链在B这里就找到了foo,不会再去A里找了。
再补充一个细节:虽然b.foo绑定的是A.foo函数,但调用时传入的self是b这个B的实例。比如:
class A: def foo(self): print(f"来自A的方法,self是{self},类型是{type(self)}") class B(A): pass b = B() b.foo() # 输出:来自A的方法,self是<__main__.B object at 0x...>,类型是<class '__main__.B'>
这说明绑定方法是把实例和基类函数结合起来,而不是简单的指针指向基类方法——它完全知道自己要操作的是哪个实例,哪怕方法定义在基类里。
内容的提问来源于stack exchange,提问作者Alex

