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 是的,float
和 int
对象是...对象。而且它们是不可变的。 Python 中的 Everything 是一个对象。您给出的示例的行为取决于实现,并且可以根据任何 python 版本进行更改,即使在次要版本更新中也是如此。但基本上,CPython 编译器通常会将不可变常量表达式优化为同一个对象。它发生的方式和时间取决于很多事情,同样,这是一个实现细节以上是关于Python:变量何时通过引用传递,何时通过值传递? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
在c / c ++中何时通过引用传递以及何时通过值传递[重复]