python:关于赋值语句的混淆:l=[a,b]=[0,1]?

python:关于赋值语句的混淆:l=[a,b]=[0,1]?,python,Python,在python 3.4交互提示中: >>> l = [a,b] = [0,1] >>> a is l[0] True >>> b is l[1] True >>> l[0] = 2 >>> a 0 >>> l [2, 1] 我假设下面的语句执行列表第一个元素的就地更改 l[0] = 2 既然变

在python 3.4交互提示中:

    >>> l = [a,b] = [0,1]
    >>> a is l[0]
    True
    >>> b is l[1]
    True
    >>> l[0] = 2  
    >>> a
    0
    >>> l
    [2, 1]
我假设下面的语句执行列表第一个元素的就地更改

    l[0] = 2 

既然变量a引用的是同一个对象,为什么它的值保持为0?这个赋值语句内部发生了什么?

a
l[0]
是同一个对象的两个名称,但是当你说
l[0]=2
时,你只是在重新定义
l[0]
a
仍然引用与以前相同的对象;只是
l[0]
发生了变化
a
指的是一个对象,而不是一个位置。

这是因为您实际上在那里创建了三个变量
a
b
l
。只有最后一个是列表。以逐行格式出现的情况如下:

a = 0
b = 1
l = [a, b] #which means l = [0, 1], not really the same referencing element a, b
如果你查一下

a is l[0]
b is l[1]
两者都返回
true
,因为它们的值相同,但同样是值,而不是引用

然后当你改变时:

l[0] = 2

只有
l[0]
中的值发生变化,它不会影响
a
。最好是使用好的调试器工具进行检查,如
PyCharm
。它在监视窗口中显示并内联变量的所有当前值。

我认为混淆是由于初始赋值:

l = [a,b] = [0,1]
这相当于:

t = [0, 1]
l = [a, b] = t
t = [0, 1]
a = t[0]
b = t[1]
l = t
l = [0, 1]
a = l[0]
b = l[1]
这反过来相当于:

t = [0, 1]
l = [a, b] = t
t = [0, 1]
a = t[0]
b = t[1]
l = t
l = [0, 1]
a = l[0]
b = l[1]
这反过来相当于:

t = [0, 1]
l = [a, b] = t
t = [0, 1]
a = t[0]
b = t[1]
l = t
l = [0, 1]
a = l[0]
b = l[1]

其余的都是这样。

最后一个例子根本不正确。由于小的
int
缓存,它会像OP一样工作,但是对于小的
int
缓存范围之外的数字,最后一个示例中的代码不会生成make
a is l[0]
true。其他三个例子有点正确(顺序可能不同,但最终的引用都会匹配),但最后一个例子非常误导。你被小的
int
缓存愚弄了。尝试使用值1000和2000<代码>a=1000,然后
b=2000
,然后
l=[10002000]
。我会等的。@ShadowRanger是的,你说得对。我没有意识到相同的整数只适用于较小的值。谢谢你的信息。我更新了我的答案。@ShadowRanger这其实很微妙。如果执行
a=1000
后接
b=1000
,则
a为b
False
。但是如果你做了
a=1000;b=1000
在同一行上,则
a是b
True
。似乎有一些每行缓存正在进行。它还解释了为什么
1000是1000
True
。是的。有一些有趣的错误关于每行常数折叠,CPython的人最近不得不修复。这里有一个有趣的例子,仍然适用于Python 3.5.1:
a=lambda:True;b=λ:1
。正如您所料,
a()
返回
True
。但是
b()
也是如此。它常量折叠两个
lambda
s,因为字节码是相同的,并且每个常量表的值都是彼此相等的(
bool
被实现为
int
的子类,其中
True
具有值
1
False
具有值
0
)。他们测试的是平等而不是身份。有趣,对吧?你用的术语似乎。。。我觉得很尴尬
a
b
是分别存储对与
l[0]
l[1]
相同对象的引用的名称。基本上,
a
l[0]
都指向(引用)一个值为
0
的单个对象,但是
a
没有对
l[0]
的引用,也没有对
a
l[0]
的引用。当您指定给
l[0]
时,它会更改
l[0]
指向的位置;它过去指向什么并不重要,因为该引用正在被替换。@programforjoy:好吧,我将其描述为“对同一对象的两个引用
0
”,而不是“附加到”。以那种方式使用“attached”使我认为
a
l[0]
属于
0
,但事实并非如此。在内部,
0
“知道”有多少东西引用了它,但它不知道哪些东西引用了它。@Ian:不,它不是那样工作的。“字面价值”在这里不是一个有意义的概念;Python不像Java语言那样区分“原语”和“高级类型”。小的
int
缓存在愚弄你。CPython维护一个IIRC,-5和260之间的所有
int
的缓存(可能是256,必须进行双重检查)<代码>是是直接指针比较;当名称绑定到同一个对象时,它只返回
True
。@Ian:这是一个常见的混淆源;我看到很多人对
有误解。与
int
str
同时发生;使用
str
,任何
str
literal(可能仅低于某个大小,未检查详细信息)实际上都是相同的
str
,这要感谢插入了literal字符串。所以你可以做
a=“abc”
b=“abc”
,并且
a是b
真的
。但是,如果创建相同的
str
值而不使用文本(并且Python的窥视孔优化器不会在内部转换为文本),则可以说,
b=''.join(“abc”)
,然后
a是b
变成
False
@Ian:真正的关键是在处理诸如
None
NotImplemented
(其中
is
是最佳解决方案)之类的单例时,或者在对象标识出于某种原因实际上很重要时,基本上只使用
is
。对象标识的一个不太常见的用法是,当您需要测试是否有人传递参数与未传递参数,但所有值都是合法的(包括
)。您可以创建一个特殊的sentinel对象,
sentinel