Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 可变类型的链式赋值_Python_Chained Assignment - Fatal编程技术网

Python 可变类型的链式赋值

Python 可变类型的链式赋值,python,chained-assignment,Python,Chained Assignment,调试一段代码时遇到此问题。如果之前没有意识到这种行为 foo = bar = [1, 2, 3] hex(id(foo)) Out[121]: '0x1f315dafe48' hex(id(bar)) Out[122]: '0x1f315dafe48' 两个“变量”都指向相同的内存位置。但是现在如果一个发生了变化,其他的也会发生变化: foo.append(4) bar Out[126]: [1, 2, 3, 4] 因此,本质上这里我们有两个名称分配给同一个变量/内存地址。这与: foo

调试一段代码时遇到此问题。如果之前没有意识到这种行为

foo = bar = [1, 2, 3]

hex(id(foo))
Out[121]: '0x1f315dafe48'
hex(id(bar))
Out[122]: '0x1f315dafe48'
两个“变量”都指向相同的内存位置。但是现在如果一个发生了变化,其他的也会发生变化:

foo.append(4)

bar
Out[126]: [1, 2, 3, 4]
因此,本质上这里我们有两个名称分配给同一个变量/内存地址。这与:

foo = [1, 2, 3]
bar = [1, 2 ,3]
hex(id(foo))
Out[129]: '0x1f315198448'
hex(id(bar))
Out[130]: '0x1f319567dc8'
在这里,对
foo
bar
的更改不会对另一个产生任何影响


所以我的问题是:为什么这个特性(可变类型的链式赋值)甚至存在于Python中?除了给你射自己的脚的工具之外,它还有什么用途吗?

它对于简单、常见的初始化非常有用,例如

foo = bar = baz = 0
所以你不必写

foo = 0
bar = 0
baz = 0
由于它是一种语法特性,因此仅对不可变类型起作用实际上是不可行的。解析器无法判断最后的表达式是可变类型还是不可变类型。你可以

def initial_value():
    if random.choice([True, False]):
        return []
    else:
        return 0

foo = bar = baz = initial_value()
initial_value()
可以返回可变或不可变的值。分配的解析器无法知道它将是什么

有很多方法可以通过多次引用可变值来打击你自己,Python不会特意阻止你。有关一些更常见的示例,请参见和

您只需记住,在链式赋值中,值表达式只计算一次。所以你的作业相当于

temp = [1, 2, 3]
foo = temp
bar = temp
而不是

foo = [1, 2, 3]
bar = [1, 2, 3]


需要记住的一条更一般的规则是Python从不自发地复制对象,您必须始终告诉它这样做。

这适用于不可变对象,因为它们是有效的指针。如果执行
foo+=1
,则
foo
现在将指向不同的内存地址,而
bar
baz
仍将指向存储值0的原始地址。它永远不会导致不可变的问题,但可变类型是另一回事。我不确定我是否同意“解析器不能判断最后的表达式是可变的还是不可变的类型”。如果解析器在赋值的另一端看到
[]
{}
,它应该立即意识到它正在处理一个可变的。
foo=bar=baz=somefunc()
这取决于
somefunc()
是否返回一个可变或不可变的对象。
foo=bar=baz=[]如果f()否则0
If
f()
已定义并且可以返回值解析器应该知道返回值的类型,不是吗?
foo=bar=[1,2,3]
的行为与行为一致,或者
bar=[1,2,3]
后跟
foo=bar
@MarkMeyer,同意。但你为什么要这么做,因为你知道对foo的任何改变都会改变bar呢?给同一个变量分配两个名称有什么意义?我不知道。我很确定我从未在现实生活中使用过这种分配模式。另一方面,我真的不希望我的代码分配(可能)大型集合而不显式复制。如果调用
list.sort(foo)
,您更希望
list.sort
函数引用与
foo
相同的列表,而不是它的副本;否则它将对自己的副本进行排序,并且
foo
保持不变。当然,
list.sort
中必须有一个局部变量,它与
foo
不同(可能称为
self
)。因此,有很多原因让两个不同的变量引用同一个可变对象。