英文:
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
问题
以下是您提供的代码的翻译部分:
#!/usr/bin/env python3
class Node:
_name: str = None
_parents = []
def __init__(self, name: str):
self._name = name
def add_parent(self, node):
self._parents.append(node)
if __name__ == "__main__":
foo = Node("foo")
bar = Node("bar")
foo.add_parent(bar)
print("= foo")
print(foo._parents)
print(list(map(lambda n: n._name, foo._parents)))
print("= bar")
print(bar._parents)
print(list(map(lambda n: n._name, bar._parents)))
and this is the result:
= foo
[<__main__.Node object at 0x7fdd66d9ac90>]
['bar']
= bar
[<__main__.Node object at 0x7fdd66d9ac90>]
['bar']
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.
如果您需要进一步的解释或帮助,请随时提问。
英文:
It's easier to explain my issue with an example so here it goes:
#!/usr/bin/env python3
class Node:
_name: str = None
_parents = []
def __init__(self, name: str):
self._name = name
def add_parent(self, node):
self._parents.append(node)
if __name__ == "__main__":
foo = Node("foo")
bar = Node("bar")
foo.add_parent(bar)
print("= foo")
print(foo._parents)
print(list(map(lambda n: n._name, foo._parents)))
print("= bar")
print(bar._parents)
print(list(map(lambda n: n._name, bar._parents)))
and this is the result:
= foo
[<__main__.Node object at 0x7fdd66d9ac90>]
['bar']
= bar
[<__main__.Node object at 0x7fdd66d9ac90>]
['bar']
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
,因此所有实例都引用同一类变量。
class Node:
_name: str = "CLASS"
_parents = []
def __init__(self, name: str):
self._name = name
def add_parent(self, node):
self._parents.append(node)
foo = Node("foo")
bar = Node("bar")
foo.add_parent(bar)
print(f"{foo._name = }")
print(f"{foo.__class__._name = }")
print(f"{id(foo._name) = }")
print(f"{id(bar._name) = }")
print(f"{id(foo._parents) = }")
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.
class Node:
_name: str = "CLASS"
_parents = []
def __init__(self, name: str):
self._name = name
def add_parent(self, node):
self._parents.append(node)
foo = Node("foo")
bar = Node("bar")
foo.add_parent(bar)
print(f"{foo._name = }")
print(f"{foo.__class__._name = }")
print(f"{id(foo._name) = }")
print(f"{id(bar._name) = }")
print(f"{id(foo._parents) = }")
print(f"{id(bar._parents) = }")
Notice how ids of _name
are different, but _parents
have the same id, meaning it's the same object.
答案2
得分: 1
foo和bar是类属性,它们在类实例之间共享
你应该在__init__
方法中定义它们,使它们成为实例属性
class Node:
def __init__(self, name: str):
self._name = name
self._parents = []
def add_parent(self, node):
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
class Node:
def __init__(self, name: str):
self._name = name
self._parents = []
def add_parent(self, node):
self._parents.append(node)
Also, notice you're using a list which can be updated by different objects
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论