Python 中有关按值调用和按引用调用的查询
Query regarding call by value and call by reference in Python
我很困惑,在Python中,哪种情况是正确的,第一种情况还是第二种情况,或者两种情况都正确?
- 为什么在第一种情况下列表
x
保持不变?
- 为什么在第二种情况下列表
x
也被修改了?
案例 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()
。 x
和 z
指向同一个列表。
z.append(4)
- 将 4 添加到 z
引用的列表中。
- 由于
z
和 x
引用同一个列表,因此 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]
我很困惑,在Python中,哪种情况是正确的,第一种情况还是第二种情况,或者两种情况都正确?
- 为什么在第一种情况下列表
x
保持不变? - 为什么在第二种情况下列表
x
也被修改了?
案例 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()
。x
和z
指向同一个列表。 z.append(4)
- 将 4 添加到z
引用的列表中。- 由于
z
和x
引用同一个列表,因此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]