为何子类Square的私有实例变量前缀仍为_Rectangle?
我定义了Rectangle类及其子类Square,将所有属性以双下划线开头声明为私有属性。但通过__dict__查看实例属性时发现,Rectangle实例与Square实例的私有属性前缀均为_Rectangle(例如均为_Rectangle__width),而非Square实例预期的_Square__width。我怀疑这与使用super()初始化Square类有关,以下是我的代码及测试结果:
class Rectangle(Base): def __init__(self, width, height, x=0, y=0, id=None): super().__init__(id) self.__width = width self.__height = height self.__x = x self.__y = y def to_dictionary(self): return self.__dict__ class Square(Rectangle): def __init__(self, size, x=0, y=0, id=None): super().__init__(size, size, x, y, id) def to_dictionary(self): return self.__dict__
测试代码:
r2 = Rectangle(5, 5, 5, 5) rectangle_dict = r2.to_dictionary() print(rectangle_dict) s2 = Square(4, 4, 4) square_dict = s2.to_dictionary() print(square_dict)
测试结果:
{'id': 1, '_Rectangle__width': 5, '_Rectangle__height': 5, '_Rectangle__x': 5, '_Rectangle__y': 5} {'id': 2, '_Rectangle__width': 4, '_Rectangle__height': 4, '_Rectangle__x': 4, '_Rectangle__y': 4}
我知道Square类中的to_dictionary方法可继承自Rectangle类,无需重新定义,但结果一致。
原因解释
Python中双下划线开头的私有属性会触发名称改写(Name Mangling),但这个改写规则的核心是:属性的改写前缀由定义该属性的类决定,而非实例所属的类。
你的代码里,__width、__height、__x、__y这些属性都是在Rectangle类的__init__方法中赋值的,所以Python会自动把这些属性名改写为_Rectangle__width这类格式——不管是Rectangle实例还是它的子类Square实例,只要是通过Rectangle的__init__初始化的这些属性,都会带上_Rectangle的前缀。
Square类的__init__只是调用了父类的初始化方法,并没有在自己的类定义里给这些私有属性赋值,所以自然不会生成_Square__xxx格式的属性。如果要让Square拥有自己的私有属性,需要在Square的__init__中单独定义,比如:
class Square(Rectangle): def __init__(self, size, x=0, y=0, id=None): super().__init__(size, size, x, y, id) self.__size = size # 这个属性会被改写为_Square__size
此时查看Square实例的__dict__,就能看到_Square__size这个属性了。
内容的提问来源于stack exchange,提问作者steve_wanash

