实例变量的前缀为什么在父类和子类中保持相同?

huangapple go评论106阅读模式
英文:

Why does the prefix for instance variables remain the same for both the parent and child class?

问题

  1. 我有两个类Rectangle矩形Square正方形)。SquareRectangle的子类
  2. 问题出在当我在任一类中使用self.__dict__语句来检查它们实例的值时它们都在关键字中带有前缀 **_Rectangle**例如矩形实例和正方形实例的宽度都会有关键字 **_Rectangle__width**我理解这是因为我将所有属性初始化为私有属性但为什么当它是正方形实例时前缀没有改变呢我假设对于正方形实例宽度关键字应该是 **_Square__width**这是因为我在使用super()函数初始化我的正方形类的值吗以下是我的代码
  3. ```python
  4. class Rectangle(Base):
  5. def __init__(self, width, height, x=0, y=0, id=None):
  6. super().__init__(id)
  7. self.__width = width
  8. self.__height = height
  9. self.__x = x
  10. self.__y = y
  11. def to_dictionary(self):
  12. return self.__dict__
  13. class Square(Rectangle):
  14. def __init__(self, size, x=0, y=0, id=None):
  15. super().__init__(size, size, x, y, id)
  16. def to_dictionary(self):
  17. return self.__dict__

我在主函数中使用以下代码测试了该函数。

  1. r2 = Rectangle(5, 5, 5, 5)
  2. rectangle_dict = r2.to_dictionary()
  3. print(rectangle_dict)
  4. s2 = Square(4, 4, 4)
  5. square_dict = s2.to_dictionary()
  6. print(square_dict)

结果是

  1. {'id': 1, '_Rectangle__width': 5, '_Rectangle__height': 5, '_Rectangle__x': 5, '_Rectangle__y': 5}
  2. {'id': 2, '_Rectangle__width': 4, '_Rectangle__height': 4, '_Rectangle__x': 4, '_Rectangle__y': 4}

所有关键字前缀都相同。为什么会这样呢?我知道我在Square类中的to_dictionary方法是不必要的,因为它可以轻松继承自Rectangle类,但结果会与上面相同。

  1. <details>
  2. <summary>英文:</summary>
  3. I have two classes, Rectangle and Square. Square is the child class to Rectangle.
  4. 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&#39;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

  1. def to_dictionary(self):
  2. return self.__dict__

class Square(Rectangle):
def init(self, size, x=0, y=0, id=None):
super().init(size, size, x, y, id)

  1. def to_dictionary(self):
  2. return self.__dict__
  1. 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)

  1. 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}

  1. 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.
  2. </details>
  3. # 答案1
  4. **得分**: 1
  5. `Square.__init__` 调用 `super()``super()` 调用 `Rectangle.__init__`,在那里分配了私有变量。私有变量只应该被定义它们的类使用。继承者无权干预它们。这实际上就是它们存在的原因。如果你希望像 `Square` 这样的继承者看到这些变量,就不应将它们设为类的私有变量。
  6. <details>
  7. <summary>英文:</summary>
  8. `Square.__init__` calls `super()` which calls `Rectangle.__init__` and that&#39;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&#39;s literally _why_ they exist. If you want inheritors like `Square` to see these variables, you shouldn&#39;t make them private to the class.
  9. </details>
  10. # 答案2
  11. **得分**: 0
  12. 这是关于在Python中如何使用“private”属性(以双下划线开头的属性)的方式。[来自文档][1]
  13. > 任何形式为__spam的标识符(至少有两个前导下划线,最多一个尾随下划线)都会在文本上替换为_classname__spam,其中classname是当前类名去掉前导下划线的部分。(...)
  14. > 名称混淆旨在为类提供一种轻松定义“private”实例变量和方法的方式,**而不必担心派生类定义的实例变量,也不必为类外部的代码修改实例变量而烦恼**。请注意,混淆规则主要设计用于避免意外情况;仍然有可能让决心坚定的人访问或修改被视为私有的变量。
  15. 因此,您“无法”覆盖这样的变量,定义`Square`中的`__width`将创建两个字段,`Rectangle__width``Square__width`
  16. [1]: https://docs.python.org/3/tutorial/classes.html#private-variables
  17. <details>
  18. <summary>英文:</summary>
  19. This is how &quot;private&quot; attributes (so the one that starts with double underscore) works in python. [From docs][1]
  20. &gt; 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. (...)
  21. &gt; 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.
  22. So you &quot;cannot&quot; override such variable, defining `__width` in `Square` will create both fields, `Rectangle__width` and `Square__width`
  23. [1]: https://docs.python.org/3/tutorial/classes.html#private-variables
  24. </details>

huangapple
  • 本文由 发表于 2023年5月26日 07:51:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76336865.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定