Why adding a object to an attribute of the another object of the same class have the side effect of adding it to both objects in python

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

Why adding a object to an attribute of the another object of the same class have the side effect of adding it to both objects in python

问题

以下是您提供的代码的翻译部分:

  1. #!/usr/bin/env python3
  2. class Node:
  3. _name: str = None
  4. _parents = []
  5. def __init__(self, name: str):
  6. self._name = name
  7. def add_parent(self, node):
  8. self._parents.append(node)
  9. if __name__ == "__main__":
  10. foo = Node("foo")
  11. bar = Node("bar")
  12. foo.add_parent(bar)
  13. print("= foo")
  14. print(foo._parents)
  15. print(list(map(lambda n: n._name, foo._parents)))
  16. print("= bar")
  17. print(bar._parents)
  18. print(list(map(lambda n: n._name, bar._parents)))
  19. and this is the result:
  20. = foo
  21. [<__main__.Node object at 0x7fdd66d9ac90>]
  22. ['bar']
  23. = bar
  24. [<__main__.Node object at 0x7fdd66d9ac90>]
  25. ['bar']
  26. why is the `bar` object added to itself too?
  27. I would expect it to be added only to foo._parents so to me this is a side effect maybe even a bug in Python.

如果您需要进一步的解释或帮助,请随时提问。

英文:

It's easier to explain my issue with an example so here it goes:

  1. #!/usr/bin/env python3
  2. class Node:
  3. _name: str = None
  4. _parents = []
  5. def __init__(self, name: str):
  6. self._name = name
  7. def add_parent(self, node):
  8. self._parents.append(node)
  9. if __name__ == &quot;__main__&quot;:
  10. foo = Node(&quot;foo&quot;)
  11. bar = Node(&quot;bar&quot;)
  12. foo.add_parent(bar)
  13. print(&quot;= foo&quot;)
  14. print(foo._parents)
  15. print(list(map(lambda n: n._name, foo._parents)))
  16. print(&quot;= bar&quot;)
  17. print(bar._parents)
  18. print(list(map(lambda n: n._name, bar._parents)))

and this is the result:

  1. = foo
  2. [&lt;__main__.Node object at 0x7fdd66d9ac90&gt;]
  3. [&#39;bar&#39;]
  4. = bar
  5. [&lt;__main__.Node object at 0x7fdd66d9ac90&gt;]
  6. [&#39;bar&#39;]

why is the bar object added to itself too?

I would expect it to be added only to foo._parents so to me this is a side effect maybe even a bug in Python.

答案1

得分: 1

_parents 被定义为类变量,因此在该类的所有实例之间共享。

实例变量需要在实例上定义,例如在 __init__ 方法中。

最初,_name 也被定义为类变量,但您立即用在实例中创建的 self._name 变量遮蔽了它。您没有重新分配 self._parents,因此所有实例都引用同一类变量。

  1. class Node:
  2. _name: str = "CLASS"
  3. _parents = []
  4. def __init__(self, name: str):
  5. self._name = name
  6. def add_parent(self, node):
  7. self._parents.append(node)
  8. foo = Node("foo")
  9. bar = Node("bar")
  10. foo.add_parent(bar)
  11. print(f"{foo._name = }")
  12. print(f"{foo.__class__._name = }")
  13. print(f"{id(foo._name) = }")
  14. print(f"{id(bar._name) = }")
  15. print(f"{id(foo._parents) = }")
  16. print(f"{id(bar._parents) = }")
英文:

_parents is defined as a class variable. As such, it is shared among all instances of this class.

Instance variables need to be defined on an instance, for example in __init__ method.

Initially _name is defined as a class variable as well, but you are immediately shadowing it with self._name variable created in an instace. You are not reassigning self._parents, so all instances refer to the same class variable.

  1. class Node:
  2. _name: str = &quot;CLASS&quot;
  3. _parents = []
  4. def __init__(self, name: str):
  5. self._name = name
  6. def add_parent(self, node):
  7. self._parents.append(node)
  8. foo = Node(&quot;foo&quot;)
  9. bar = Node(&quot;bar&quot;)
  10. foo.add_parent(bar)
  11. print(f&quot;{foo._name = }&quot;)
  12. print(f&quot;{foo.__class__._name = }&quot;)
  13. print(f&quot;{id(foo._name) = }&quot;)
  14. print(f&quot;{id(bar._name) = }&quot;)
  15. print(f&quot;{id(foo._parents) = }&quot;)
  16. print(f&quot;{id(bar._parents) = }&quot;)

Notice how ids of _name are different, but _parents have the same id, meaning it's the same object.

答案2

得分: 1

foo和bar是类属性,它们在类实例之间共享
你应该在__init__方法中定义它们,使它们成为实例属性

  1. class Node:
  2. def __init__(self, name: str):
  3. self._name = name
  4. self._parents = []
  5. def add_parent(self, node):
  6. self._parents.append(node)

另外,请注意你正在使用一个列表,这个列表可以被不同的对象更新

英文:

foo and bar are class attributes and are shared between class instances
You should define them in the __init__ method to make them instance attributes

  1. class Node:
  2. def __init__(self, name: str):
  3. self._name = name
  4. self._parents = []
  5. def add_parent(self, node):
  6. self._parents.append(node)

Also, notice you're using a list which can be updated by different objects

huangapple
  • 本文由 发表于 2023年4月13日 19:03:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/76004670.html
匿名

发表评论

匿名网友

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

确定