python是否通过引用,值或对象传递?即使阅读了一些帖子,也很令人困惑。我还是不明白我是怎么得到怪异结果的。谁能帮助解释奇怪的结果是如何产生的以及如何获得正确的结果?
我尝试在python中旋转2D列表。如情况1所示,当没有调用任何函数时,我得到正确的结果。但是,当我将代码放在函数中时,它返回一个奇怪的结果,这不是我所期望的。为什么在情况2 [[9,6,3],[8,5,2],[7,4,1]]下输出?它从哪里来的?
QA
答案 0 :(得分:1)
Python通过引用传递。如果将对象传递给函数,然后修改该对象,则该函数结束后,该对象将保持修改状态。例如:
def f(a):
a[1] = 'b'
x = [1, 2, 3]
f(x)
print(x)
# [1, 'b', 3]
问题是python 不要中的许多东西都修改了该对象。字符串几乎是完全不变的,例如-您可以对字符串执行的大多数操作,以及可以对字符串进行调用的大多数函数,都可以在不更改原始字符串的情况下返回新的(经过修改的)字符串。这包括串联,反转和切片。
列表比字符串的可变性要大得多,可以通过更改单个索引(例如my_list[1] = 'b'
)或使用.append()
或.extend()
之类的方法直接进行修改。但是作为一个整体,很多可迭代的事情并不会改变列表本身。这包括串联,反转和切片。
赋值运算符=
肯定不会修改左侧的对象;而是替换。
所以没有得到相同输出的原因是此行:
matrix = matrix[::-1]
这不会修改原始的matrix
-而是通过切片matrix
创建一个新列表,并将其分配回matrix
。当您在函数外部运行代码时,在命名空间中只有一个matrix
引用,并且该引用被替换了,因此您再也看不到任何区别。但是,函数内部引用的matrix
是一个独立的命名空间,而不是函数外部的命名空间。它从指向同一对象开始,但是在此行中,您将该引用指向另一个对象。然后,您可以继续修改其他对象,而保留原始对象。一个(很有帮助的)注释:
# global scope
# matrix --> some object with address 0x001
def rotate(matrix):
# local scope
# matrix --> 0x001 (the reference that was passed in)
matrix = matrix[::-1] # the slice creates a new object 0x002
# matrix --> 0x002
...
然后继续修改matrix
时,您正在修改0x002
。一切都很好,但是这些更改并没有影响0x001
。
有一些方法可以解决此问题-例如,就地反向,而不是使用切片来获取原始列表的反向版本:
def reverse_in_place(lst):
for i in range(len(lst) // 2):
lst[i], lst[-i-1] = lst[-i-1], lst[i]
但是正如@Jmonsky在他们的答案中指出的那样,返回修改后的值比修改传入的值更为常规,但有一些特定的例外。
答案 1 :(得分:0)
您可以通过返回矩阵的旋转副本而不是对其进行突变来解决此问题。
def rotate(matrix):
print('1',matrix)
matrix = matrix[::-1]
print('2',matrix)
for i in range(len(matrix)):
for j in range (len(matrix[0])):
if i<=j:
matrix[j][i],matrix[i][j] =matrix[i][j], matrix[j][i]
print('3',matrix)
return matrix
mat = [[1,2,3],[4,5,6],[7,8,9]]
mat = rotate(mat)
print(mat)
输出
1 [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2 [[7, 8, 9], [4, 5, 6], [1, 2, 3]]
3 [[7, 4, 1], [8, 5, 2], [9, 6, 3]]
[[7, 4, 1], [8, 5, 2], [9, 6, 3]]