Python函数通过引用,值或对象进行调用

时间:2019-07-12 18:34:09

标签: python

python是否通过引用,值或对象传递?即使阅读了一些帖子,也很令人困惑。我还是不明白我是怎么得到怪异结果的。谁能帮助解释奇怪的结果是如何产生的以及如何获得正确的结果?

我尝试在python中旋转2D列表。如情况1所示,当没有调用任何函数时,我得到正确的结果。但是,当我将代码放在函数中时,它返回一个奇怪的结果,这不是我所期望的。为什么在情况2 [[9,6,3],[8,5,2],[7,4,1]]下输出?它从哪里来的?

QA

2 个答案:

答案 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]]