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评论71阅读模式
英文:

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__ == &quot;__main__&quot;:

    foo = Node(&quot;foo&quot;)
    bar = Node(&quot;bar&quot;)

    foo.add_parent(bar)

    print(&quot;= foo&quot;)
    print(foo._parents)
    print(list(map(lambda n: n._name, foo._parents)))

    print(&quot;= bar&quot;)
    print(bar._parents)
    print(list(map(lambda n: n._name, bar._parents)))

and this is the result:

= foo
[&lt;__main__.Node object at 0x7fdd66d9ac90&gt;]
[&#39;bar&#39;]
= bar
[&lt;__main__.Node object at 0x7fdd66d9ac90&gt;]
[&#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,因此所有实例都引用同一类变量。

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 = &quot;CLASS&quot;
    _parents = []

    def __init__(self, name: str):
        self._name = name

    def add_parent(self, node):
        self._parents.append(node)

foo = Node(&quot;foo&quot;)
bar = Node(&quot;bar&quot;)

foo.add_parent(bar)

print(f&quot;{foo._name = }&quot;)
print(f&quot;{foo.__class__._name = }&quot;)

print(f&quot;{id(foo._name) = }&quot;)
print(f&quot;{id(bar._name) = }&quot;)

print(f&quot;{id(foo._parents) = }&quot;)
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__方法中定义它们,使它们成为实例属性

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

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:

确定