Python添加到字典中的意外列表[重复]

Posted

技术标签:

【中文标题】Python添加到字典中的意外列表[重复]【英文标题】:Python adding to unintended list in a dictionary [duplicate] 【发布时间】:2022-01-19 10:49:27 【问题描述】:

想知道是否有人可以向我解释为什么会发生这种情况。

class Animal:
    def __init__(self, name='', child=[]):
        self.name=name
        self.child=child

val = []


dog = Animal(name="Foo")
val.append(dog.__dict__)

cat = Animal(name='John')
cat.child.append('Doe')
val.append(cat.__dict__)

print(val)

结果:

['name': 'Foo', 'child': ['Doe'], 'name': 'John', 'child': ['Doe']]

预期:

['name': 'Foo', 'child': [], 'name': 'John', 'child': ['Doe']]

我假设它与内存分配有关,但我无法理解它是如何工作的。

提前致谢!

【问题讨论】:

不要使用像child=[]这样的可变默认参数 【参考方案1】:

字典是引用类型变量。引用是指一个值(对象)在内存中的特定位置的名称。这意味着在您实例化一个 dict 后,它总是指向内存中的相同位置。无论您是否编辑您的字典。所以一个简单的代码解决方案是:

class Animal:

    def __init__(self, name='', child=None):
        self.name=name
        self.child=child
        if self.child is None:
            self.child = []
    

val = []

dog = Animal(name="Foo")
print(dog.__dict__)
val.append(dog.__dict__)

cat = Animal(name='John')
cat.child.append('Doe')
val.append(cat.__dict__)

print(val)

这样每次从 Animal 类创建对象时,它都会在内存中保留一个新位置。

【讨论】:

“字典是引用类型变量”——这有点误导。无论数据类型如何,所有 Python 名称(如果您愿意,也可以是变量)都是对内存中某个对象的单向引用。它可以是一个列表,int,dict,...与名称无关。您可能想说的是:“dicts 是可变的”。 @timgeb 是的,完全正确。 dict 是可变的,你必须完全理解 python 是如何思考和作用于“可变”的。证明这一点的简单方法是它存在于内存中,并且每次你指的是同一个地方。【参考方案2】:

您可以使用数据类并为列表设置默认工厂

from dataclasses import dataclass, field, asdict
from typing import List

@dataclass
class Animal:
    name : str 
    children : List[str] = field(default_factory=list)

a=Animal(name="Foo")
b=Animal(name='John')
b.children.append('Doe')

val = [
    asdict(x) for x in [a,b]
]

print(val)

【讨论】:

以上是关于Python添加到字典中的意外列表[重复]的主要内容,如果未能解决你的问题,请参考以下文章

Python编程入门到实践 - 笔记( 6 章)

附加到 Python 字典中的列表 [重复]

给定一个字符串列表,如果任何值等于列表中的值,我想将字典的值添加到新字典中[重复]

在python中怎么把列表中的元素添加到字典中

在python中怎么把列表中的元素添加到字典中

Python:如何将字典中的值提取到列表中->当前在结果中获取 dict_values() [重复]