Python 中有关按值调用和按引用调用的查询

Query regarding call by value and call by reference in Python

我很困惑,在Python中,哪种情况是正确的,第一种情况还是第二种情况,或者两种情况都正确?

案例 1:

x = [0, 1, 2]

def cleanIt(y):
    y = []
    return y

print(cleanIt(x)) #[]
print(x)          #[0, 1, 2]

案例 2:

x = [0, 1, 2]
    
def appendOne(z):
    z.append(4)
    return z

print(appendOne(x)) #[0, 1, 2, 4]
print(x)            #[0, 1, 2, 4]

Python 的行为类似于 pass-by-object-reference。因此,您真正传递给函数的实际上是对您提供的对象的引用。在第一个示例中,您传递了一个指向 x 所在内存地址的引用。但是,当您进行赋值操作 y = [] 时,您只需更改您的引用指向的内存地址。您不更改 x 的内容。在第二个示例中,您调用方法 append()。在这种情况下,您可以为您的引用指向的内存地址中存在的对象调用此方法。
这些在开始时可能会令人困惑,但您应该记住,将您的变量直接分配给其他东西实际上并不会改变您的变量,它会改变您的引用指向的位置。但是,使用一种方法,修改您的变量会更新它。

我已经使用 id() 让您清楚地了解参考文献。 id() returns 传递给它的参数的内存地址。

案例一

x = [0, 1, 2]
    
print(id(x))  
def cleanIt(y):
    print(id(y))
    y = []
    print(id(y))
    return y

print(cleanIt(x))
print(x)
Output:

139677941202304
139677941202304
139677940574528
[]
[0, 1, 2]
  • 您将 x 的引用传递给 cleanIt
  • y = [] - 完全创建一个新列表。这与x无关。 参见上面的参考资料。
  • return y - 您 return 新创建的列表,即 y = []
  • 由于x没有变化,所以会保留初始值。

案例 2

x = [0, 1, 2]
print(id(x))

def appendOne(z):
    print(id(z))
    z.append(4)
    print(id(z))
    return z

print(appendOne(x))
print(x)
Output

139677940574912
139677940574912
139677940574912
[0, 1, 2, 4]
[0, 1, 2, 4]
  • 您将 x 的引用传递给 appendOne()xz 指向同一个列表。
  • z.append(4) - 将 4 添加到 z 引用的列表中。
  • 由于 zx 引用同一个列表,因此 z 中所做的更改也会反映在 x 中。 参见上面的参考资料。

在 Python 中,值通过对象引用发送到函数。

请阅读 this 以了解有关此概念的更多信息。

编辑:

如果我想让x不变,而z应该是[0,1,2,4],那么我应该如何修改python代码?

你可以这样做。

x = [0, 1, 2]
print(id(x))

def appendOne(z):
    print(id(z))
    # Creates a new list with contents of x.
    z = list(z)
    z.append(4)
    print(id(z))
    return z

print(appendOne(x))
print(x)
Output

140368975642112
140368975642112
140368975011392
[0, 1, 2, 4]
[0, 1, 2]