附加到空列表和重新分配它有什么区别?

What is the difference between appending to an empty list and reassigning it?

如果我们创建一个空列表,那么我们可以通过附加 "something"

来填充这个列表
list_ex1 = []
list_ex1.append(1)
print(list_ex1)
[1]

或者我们可以重新分配一个空列表作为相同的 "something"。

list_ex2 = []
list_ex2 = [1]
print(list_ex2)
[1]

很好,我们得到了相同的结果。然而,一定有一些非常不同的事情在后台发生。当我使用 tkinter 创建一个带有一些按钮的简单 UI 时,这一点变得很明显。

def Multi_Import_Match(imp):
    imp_fill = []
    win = Tk()
    win.title('Select Name')
    win.geometry("500x100")
    b = []

    def but_call(imp):
        imp_fill.append(imp) # Here is where the problem became apparent!!
        win.destroy()

    for i in range(0,len(imp)):
        b.append(Button(win, text=imp[i], command=lambda i=i: but_call(imp[i])))
        b[i].pack()
    mainloop()
    return imp_fill

在使用 imp_fill = imp 时,我努力了一段时间才从 UI 获得预期的输出,但它只返回了一个空列表。使用 imp_fill.append(imp) 代码可以完美运行并返回我想要的字符串。 为什么附加有效而重新分配无效?

注意:变量 imp 是一小串字符串。

这里的问题是范围。如果找不到名称的本地定义,Python 将搜索外层范围。这就是为什么它可以工作:

val = "hello"
def print_val():
    print(val)
print_val()
# hello

不过,由于列表是可变的,因此这会变得更加混乱。这意味着如果您从一个函数内追加到一个列表,您 在原始范围内影响它。看到这个:

val = []
def print_val():
    val.append("hello")
    print(val)

print(val)
# []
print_val()
# ['hello']
print(val)
# ['hello']

该列表最初是空的,但在调用 print_val 后该列表被追加到。这会影响实际列表,这反过来意味着当您正常打印它时,它包含 'hello'

在您的情况下,如果您只是在函数内部执行了 val = ['hello'] 的等效操作,那只会影响 val 函数中的值,原始作用域名称没有任何变化。解决方案是使用 return [val] 从函数范围获取值,或者像您一样使用 append,这会修改函数外部存在的实际值。

首先,通过阅读这段代码,您确实应该更改 but_call() 函数的参数名称以避免混淆。该参数似乎是 list imp 的一个元素,而不是您的变量 imp 本身。清晰是这里的关键。

其次,你说的不对:

imp_fill = impimp 的值(无论它是什么可能是 - liststrintobject、...)

imp_fill = [imp]fill_imp 的预先存在的值替换为具有一个元素的 list - imp

的值

imp_fill.append(imp) 取先前存在的 list 并将其扩展 1 个元素,即 imp

的值

所以:

>>> a = [2]
>>> a = [9, 5]
>>> print(a)
[9, 5]

>>> a = [2]
>>> a = 943
>>> print(a)
943

>>> a = [2]
>>> a.append(98)
>>> print(a)
[2, 98]

不同之处在于列表是一个可变对象。因此,当您 修改 对象时,对同一对象的其他引用会相应更改,但当您影响对不同对象的引用时,它们将保持不变

让我们将您的示例与替代参考一起使用:

>>> list_ex1 = []
>>> old = list_ex1
>>> list_ex1.append(1)
>>> print(list_ex1)
[1]
>>> old
[1]
>>> old is list_ex1
True

>>> list_ex2 = []
>>> old2 = list_ex2
>>> list_ex2 = [1]
>>> print(list_ex2)
[1]
>>> old2
[]
>>> old2 is list_ex2
False

在你的例子中修改带有append的列表也修改了原始对象,而影响它只改变了一个本地复制并保持原始对象不变。