英文:
Why does the prefix for instance variables remain the same for both the parent and child class?
问题
我有两个类,Rectangle(矩形)和Square(正方形)。Square是Rectangle的子类。
问题出在当我在任一类中使用self.__dict__语句来检查它们实例的值时,它们都在关键字中带有前缀 **_Rectangle**。例如,矩形实例和正方形实例的宽度都会有关键字 **_Rectangle__width**。我理解这是因为我将所有属性初始化为私有属性,但为什么当它是正方形实例时前缀没有改变呢?我假设对于正方形实例,宽度关键字应该是 **_Square__width**。这是因为我在使用super()函数初始化我的正方形类的值吗?以下是我的代码。
```python
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类,但结果会与上面相同。
<details>
<summary>英文:</summary>
I have two classes, Rectangle and Square. Square is the child class to Rectangle.
My issue is when I put in a self.__dict__ statement for either class, to check the values for their instances, both have the prefix **_Rectangle** in their keywords. Example, the width for a rectangle instance and square instance would both have the keyword **_Rectangle__width**. I get the prefix is due to me initializing all attributes as private attributes, but why doesn't the prefix change when it is a square instance. I assume for a square instance the width keyword should be **_Square__width**. Is it cause i am initializing the values for my square class using the super() function? Here is my code.
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__
I tested the function in main using the following code.
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)
The result was
{'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}
All the keyword prefixes are the same. Why is that? And I know the to_dictionary method in my Square class is unnecessary as it could easily inherit the same from the Rectangle class, but the results would be the same as above.
</details>
# 答案1
**得分**: 1
`Square.__init__` 调用 `super()`,`super()` 调用 `Rectangle.__init__`,在那里分配了私有变量。私有变量只应该被定义它们的类使用。继承者无权干预它们。这实际上就是它们存在的原因。如果你希望像 `Square` 这样的继承者看到这些变量,就不应将它们设为类的私有变量。
<details>
<summary>英文:</summary>
`Square.__init__` calls `super()` which calls `Rectangle.__init__` and that's where the private variables are assigned. Private variables should only be used by the class that defines them. Inheritors have no business fiddling with them. That's literally _why_ they exist. If you want inheritors like `Square` to see these variables, you shouldn't make them private to the class.
</details>
# 答案2
**得分**: 0
这是关于在Python中如何使用“private”属性(以双下划线开头的属性)的方式。[来自文档][1]
> 任何形式为__spam的标识符(至少有两个前导下划线,最多一个尾随下划线)都会在文本上替换为_classname__spam,其中classname是当前类名去掉前导下划线的部分。(...)
> 名称混淆旨在为类提供一种轻松定义“private”实例变量和方法的方式,**而不必担心派生类定义的实例变量,也不必为类外部的代码修改实例变量而烦恼**。请注意,混淆规则主要设计用于避免意外情况;仍然有可能让决心坚定的人访问或修改被视为私有的变量。
因此,您“无法”覆盖这样的变量,定义`Square`中的`__width`将创建两个字段,`Rectangle__width`和`Square__width`。
[1]: https://docs.python.org/3/tutorial/classes.html#private-variables
<details>
<summary>英文:</summary>
This is how "private" attributes (so the one that starts with double underscore) works in python. [From docs][1]
> Any identifier of the form __spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classname__spam, where classname is the current class name with leading underscore(s) stripped. (...)
> Name mangling is intended to give classes an easy way to define “private” instance variables and methods, **without having to worry about instance variables defined by derived classes**, or mucking with instance variables by code outside the class. Note that the mangling rules are designed mostly to avoid accidents; it still is possible for a determined soul to access or modify a variable that is considered private.
So you "cannot" override such variable, defining `__width` in `Square` will create both fields, `Rectangle__width` and `Square__width`
[1]: https://docs.python.org/3/tutorial/classes.html#private-variables
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论