为啥这个参数列表在 Python 中不会改变?
Posted
技术标签:
【中文标题】为啥这个参数列表在 Python 中不会改变?【英文标题】:Why this parameter list doesn't change in Python?为什么这个参数列表在 Python 中不会改变? 【发布时间】:2020-03-11 02:39:04 【问题描述】:我创建了一个函数 f,它使用一个二维列表作为参数,但是在这个函数之后,列表根本没有改变。 如下代码:
def f(t: [[int]]):
for eachrow in t:
eachrow = eachrow[1:]
eachrow.append(0)
A = [[2, 10, 0], [3, 1, 2], [3, 2, 1]]
f(A)
print(A) # -> [[2, 10, 0], [3, 1, 2], [3, 2, 1]]
【问题讨论】:
你只是更新循环变量,而不是输入参数 @cricket_007eachrow
最初是 t
中的一个项目,但切片会覆盖它。我发布了一个关于这个的答案。
顺便说一句,欢迎来到 Stack Overflow ClassicalPi!查看tour。
注意,这不是正确的类型注释:t: [[int]]
应该是t: typing.List[typing.List[int]]
【参考方案1】:
在eachrow = eachrow[1:]
中分配给eachrow
会覆盖它。因此,要删除第一个元素,您可以改用del
,或row.pop
或slice assignment。
def f(t):
for row in t:
del row[0] # OR row.pop(0) OR row[:] = row[1:]
row.append(0)
A = [[2, 10, 0], [3, 1, 2], [3, 2, 1]]
f(A)
print(A) # -> [[10, 0, 0], [1, 2, 0], [2, 1, 0]]
【讨论】:
从技术上讲,并不是切片在进行复制,而是对局部变量进行赋值。如果循环体改为eachrow = 0
,您将得到相同的结果。
@wmorrell 你是对的!但是为什么分配给切片有效呢?是不是因为它分配给列表的“内部”而不是名称?
@wjandrea 这是切片赋值符号:row[:] = row[1:]
,它与“分配给切片”不同,也就是说,它不会创建切片(这只是一个新列表)并分配给该新列表,而是简单地修改为原始列表
@wmorrell 要清楚,右侧的eachrow[1:]
确实创建了一个切片,即一个全新的list
对象
说一个全新的list
对象有点误导。切片创建一个新的slice
,它引用原始的list
项。项目本身不会被复制,这是大多数人在说“new list
object”时所期望的。换句话说,a = row[:]
与 a = list(row)
不同。【参考方案2】:
如果您将更改结果打印到eachrow
,您会看到您正在更新eachrow
变量,但这不会影响原始t
变量。
def f(t):
for eachrow in t:
eachrow = eachrow[1:]
eachrow.append(0)
print(eachrow)
>>> f(A)
[10, 0, 0]
[1, 2, 0]
[2, 1, 0]
如果你想影响数组本身,你应该像这样修改数组:
def f(t):
for row_number in range(len(t)):
t[row_number] = t[row_number][1:]
t[row_number].append(0)
【讨论】:
问题不是对t
的迭代,而是切片。我发布了一个关于这个的答案。顺便说一句,列表是可迭代的,而不是迭代器,因为它不会耗尽;而且我认为 Python 没有指针 - Python 名称更像是参考 IIRC。但是索引t
是解决问题的完美方法。
" 该数组元素的迭代器是该列表元素的副本,"绝对不正确。它们不是副本。将任何可变变量放在一个列表中,比如另一个列表:data = [[], []]
然后执行for x in data: x.append(0)
然后打印data
,您会看到外部列表中的列表都已被修改。
注意!已在答案中修复。
感谢你们@wjandrea 和 juanpa 看到这个。
@j6m8 哎呀,我错了,不是切片,而是分配。 wmorrel 纠正了我,我更新了我的答案。以上是关于为啥这个参数列表在 Python 中不会改变?的主要内容,如果未能解决你的问题,请参考以下文章
Python,明明只append了一次,为啥所有子列表都变了啊.jpg