附加到空列表和重新分配它有什么区别?
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 = imp
用 imp
的值(无论它是什么可能是 - list
、str
、int
、object
、...)
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
的列表也修改了原始对象,而影响它只改变了一个本地复制并保持原始对象不变。
如果我们创建一个空列表,那么我们可以通过附加 "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 = imp
用 imp
的值(无论它是什么可能是 - list
、str
、int
、object
、...)
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
的列表也修改了原始对象,而影响它只改变了一个本地复制并保持原始对象不变。