【问题标题】:Is there a difference between the two? [duplicate]两者有区别吗? [复制]
【发布时间】:2013-11-22 09:27:35
【问题描述】:

代码 A:

lst = [1, 2, 3]
for i in range(10):
    lst+= ["42"]

代码 B:

lst = [1, 2, 3]
for i in range(10):
    lst = lst + ["42"]

我知道输出是一样的,但是这两个列表的构建方式有区别吗? 后面到底发生了什么?

【问题讨论】:

    标签: python arrays memory-management immutability


    【解决方案1】:

    当你这样做时

    lst += ["42"]
    

    您正在改变 lst 并在其末尾附加“42”。但是当你说,

    lst = lst + ["42"]
    

    您正在使用lst"42" 创建一个新列表,并将新列表的引用分配给lst。试试这个程序以更好地理解这一点。

    lst = ["1"]
    print(id(lst))
    lst += ["2"]
    print(id(lst))
    lst = lst + ["3"]
    print(id(lst))
    

    前两个 id 相同,但最后一个不同。因为,创建了一个新列表,lst 现在指向该新列表。

    不知道这两者之间的区别会产生问题,当您将列表作为参数传递给函数并将项目附加到它时,在这样的函数内部

    def mutate(myList):
        myList = myList + ["2"] # WRONG way of doing the mutation
    tList = ["1"]
    mutate(tList)
    print(tList)
    

    你仍然会得到['1'],但如果你真的想改变myList,你可以这样做

    def mutate(myList):
        myList += ["2"] # Or using append function
    tList = ["1"]
    mutate(tList)
    print(tList)
    

    将打印['1', '2']

    【讨论】:

    • 您是否碰巧知道 Python 语言定义是否保证当您执行lst = lst + ["3"] 时 id 会发生变化,或者这是否留给实现?我之所以问,是因为原则上 Python 的引用计数实现可能会注意到 lst 在该操作开始时的引用计数为 1 并且被分配回其唯一的引用者,因此作为优化想要重用目的。当然它可以重用用于数组的底层内存,但我想知道语言是否允许它也重用 list 本身。
    • @SteveJessop 据我所知,id 的实现依赖于 python 实现。但是,在 CPython 中,我确信 id 在我们执行该操作时会发生变化。因为,在 CPython 中,id 返回对象的内存地址。
    • 通过我上面描述的假设优化,新列表的地址将与旧列表相同。所以 CPython 上 id 发生变化的原因不是 CPython 使用地址作为 id,而是它没有进行优化。 id 必须为不同的对象返回不同的值,我的问题是是否允许 Python 实现实际上为新对象提供与在同一语句中销毁的旧对象相同的地址(因为它的引用计数为 0)。
    猜你喜欢
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    • 2019-11-15
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 2013-05-28
    • 1970-01-01
    相关资源
    最近更新 更多