Python:变量何时通过引用传递,何时通过值传递? [复制]

Posted

技术标签:

【中文标题】Python:变量何时通过引用传递,何时通过值传递? [复制]【英文标题】:Python : When is a variable passed by reference and when by value? [duplicate] 【发布时间】:2012-03-30 14:08:52 【问题描述】:

可能重复:Python: How do I pass a variable by reference?

我的代码:

locs = [ [1], [2] ]
for loc in locs:
    loc = []

print locs
# prints => [ [1], [2] ]

为什么loc 不是locs 元素的引用?

Python:除非明确复制,否则所有内容都作为引用传递[这不是真的吗? ]

请解释一下..python如何决定引用和复制

更新:

怎么办?

def compute(ob):
   if isinstance(ob,list): return process_list(ob)
   if isinstance(ob,dict): return process_dict(ob)

for loc in locs:
   loc = compute(loc)  # What to change here to make loc a reference of actual locs iteration ?
locs 必须包含最终处理的响应! 我不想使用enumerate,没有它可以吗?

【问题讨论】:

一切都是按值传递的,但每个值都只是一个引用;) 【参考方案1】:

一切都是通过对象传递的。重新绑定和变异是不同的操作。

locs = [ [1], [2] ]
for loc in locs:
    del loc[:]

print locs

【讨论】:

【参考方案2】:

当你说

loc = []

您正在将 loc 变量重新绑定到新创建的空列表

也许你想要

loc[:] = []

将 loc 的切片(恰好是整个列表)分配给空列表

【讨论】:

我相信这最后一个例子就是 OP 想要的!【参考方案3】:

在 Python 中,从引用或值的角度来思考是没有帮助的。两者都不正确。

在 Python 中,变量只是名称。在您的 for 循环中,loc 只是一个指向列表中当前元素的名称。执行 loc = [] 只需重新绑定名称 loc 到不同的列表,保留原始版本。

但由于在您的示例中,每个元素都是一个列表,您实际上可以 mutate 该元素,这将反映在原始列表中:

for loc in locs:
    loc[0] = loc[0] * 2

【讨论】:

阅读 Idiomatic Python 可能会有所帮助 - "other languages have variables, Python has labels." 其余部分也很好阅读。 ;) 如何修改容器的每个元素? \ @Yugal 我上面写的哪一部分不清楚? 一般来说,我只想处理我的容器的每个元素。那么,如何实现呢?如果一切都是一个标签,当实际想要编辑元素时似乎是一个缺点。 @YugalJindle :要修改 列表 中的元素,请使用方括号引用该列表中的项目。【参考方案4】:

Effbot(又名 Fredrik Lundh)将 Python 的变量传递风格描述为按对象调用:http://effbot.org/zone/call-by-object.htm

对象在堆上分配,指向它们的指针可以在任何地方传递。

当您进行x = 1000 之类的赋值时,会创建一个字典条目,将当前命名空间中的字符串“x”映射到指向包含一千的整数对象的指针。 当您使用x = 2000 更新“x”时,会创建一个新的整数对象,并且字典会更新为指向新对象。旧的 1000 个对象没有改变(可能存在也可能不存在,具体取决于是否有其他对象引用该对象)。 当您执行y = x 之类的新分配时,会创建一个新的字典条目“y”,它指向与“x”条目相同的对象。 字符串和整数等对象是不可变的。这仅仅意味着没有方法可以在创建对象后更改它。例如,一旦创建了整数对象一千,它就永远不会改变。数学是通过创建新的整数对象来完成的。 像列表这样的对象是可变的。这意味着对象的内容可以被任何指向对象的东西改变。例如,x = []; y = x; x.append(10); print y 将打印 [10]。空列表已创建。 “x”和“y”都指向同一个列表。 append 方法改变(更新)列表对象(就像向数据库添加记录),结果对“x”和“y”都可见(就像数据库更新对到该数据库的每个连接)。

希望能为您澄清问题。

【讨论】:

【参考方案5】:

为什么 loc 不是 locs 元素的引用?

。或者至少,它与 Python 中的所有其他变量具有相同的意义。 Python 变量是名称,而不是存储loc 是用来指代[[1,2], [3,4]] 的元素的名称,而locs 是指代整个结构的名称。

loc = []

并不意味着“查看loc 命名的东西,并使其变成[]”。它不能意味着,因为 Python 对象不能做这样的事情。

相反,它的意思是“使loc 不再是它当前名称的事物的名称,而是开始成为[] 的名称”。 (当然,它指的是那里提供的特定[],因为通常内存中可能有多个相同的对象。)

locs 的内容自然不会因此而改变。

【讨论】:

【参考方案6】:

Python 中的一切都是按值传递和赋值的,就像 Java 中的一切都按值传递和赋值一样。 Python 中的每个值都是对象的引用(指针)。对象不能是值。赋值总是复制值(这是一个指针);因此,两个这样的指针可以指向同一个对象。对象永远不会被复制,除非你明确地复制它们。

对于您的情况,循环的每次迭代都会将列表的一个元素分配给变量loc。然后将其他内容分配给变量loc。所有这些值都是指针;您正在分配指针;但您不会以任何方式影响任何对象。

【讨论】:

在我看来 - 你描述得最好。只需告诉我问题更新的答案——你错过的那部分。 那么整数和浮点数会发生什么?它们只是被认为是不可变的对象吗? python 如何管理它,因为我确信它不能在内存中保存所有可以想象的数字以供引用。 @AndrewS:整数和浮点数确实是不可变的(应该很明显,它们没有改变自身的方法)。我不确定您评论的第二部分是什么意思。 @AndrewS:也许它们是一样的,也许它们不是。为什么这有关系?这与赋值的可变性或语义无关。 @AndrewS 是的,floatint 对象是...对象。而且它们是不可变的。 Python 中的 Everything 是一个对象。您给出的示例的行为取决于实现,并且可以根据任何 python 版本进行更改,即使在次要版本更新中也是如此。但基本上,CPython 编译器通常会将不可变常量表达式优化为同一个对象。它发生的方式和时间取决于很多事情,同样,这是一个实现细节

以上是关于Python:变量何时通过引用传递,何时通过值传递? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

函数何时值传递,何时指针,何时引用传递总结

在c / c ++中何时通过引用传递以及何时通过值传递[重复]

PHP 中的数组是作为值复制还是作为对新变量的引用,以及何时传递给函数?

何时在 PHP 中通过引用传递

带有引用参数的 foreach 何时危险?

何时重载按引用传递(左值和右值)优于按值传递?