python中可变元组组件的赋值:bug?特写?

python中可变元组组件的赋值:bug?特写?,python,tuples,immutability,pep,Python,Tuples,Immutability,Pep,我们知道Python元组是不可变的,很好。当我试图更改元组组件的引用时,我得到了一个异常,正如预期的那样。出乎意料的是,不管异常如何,组件都会发生更改,而我认为元组不变性保证了对象不可变 它是一个bug、特性还是一个PEP In [6]: x=([1],) In [7]: type(x) Out[7]: tuple In [8]: x[0]+=[2,3] -----------------------------------------------------------------------

我们知道Python元组是不可变的,很好。当我试图更改元组组件的引用时,我得到了一个异常,正如预期的那样。出乎意料的是,不管异常如何,组件都会发生更改,而我认为元组不变性保证了对象不可变

它是一个bug、特性还是一个PEP

In [6]: x=([1],)
In [7]: type(x)
Out[7]: tuple
In [8]: x[0]+=[2,3]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-a73186f99454> in <module>()
----> 1 x[0]+=[2,3]

TypeError: 'tuple' object does not support item assignment   
In [9]: x
Out[9]: ([1, 2, 3],)
[6]中的
:x=([1],)
In[7]:类型(x)
Out[7]:元组
在[8]中:x[0]+=[2,3]
---------------------------------------------------------------------------
TypeError回溯(最近一次调用上次)
在()
---->1 x[0]+=[2,3]
TypeError:“tuple”对象不支持项分配
在[9]:x中
Out[9]:([1,2,3],)
这里更简单:

tup = ([],[])
tup[0].append(0)
tup[1].append(1)
print tup
打印出来

([0],[1])
元组不变性意味着组成元组的对象不能更改为不同的对象。这并不意味着不能修改它们的值

说到这里,你发现了一个非常有趣的(如果是这个词的话)角落案例,它基本上可以翻译为:

x = tup[0]
x += [2,3]
tup[0] = x
因此,前两行按预期工作,然后出现异常。

这里更简单:

tup = ([],[])
tup[0].append(0)
tup[1].append(1)
print tup
打印出来

([0],[1])
元组不变性意味着组成元组的对象不能更改为不同的对象。这并不意味着不能修改它们的值

说到这里,你发现了一个非常有趣的(如果是这个词的话)角落案例,它基本上可以翻译为:

x = tup[0]
x += [2,3]
tup[0] = x
因此,前两行按预期工作,然后出现异常。

有趣的一点

它这样做的原因是

x[0]+=[2,3]
转化为

x[0] = x[0].__iadd__([2,3])
这意味着它首先调用
\uuuu iadd\uuuu
,修改列表,然后才尝试对元组执行非法赋值

(当然,解决问题很容易(例如@luispedro的答案),但我知道你的问题不是如何解决问题。)

它是一个bug、特性还是一个PEP

In [6]: x=([1],)
In [7]: type(x)
Out[7]: tuple
In [8]: x[0]+=[2,3]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-a73186f99454> in <module>()
----> 1 x[0]+=[2,3]

TypeError: 'tuple' object does not support item assignment   
In [9]: x
Out[9]: ([1, 2, 3],)
很难说。我倾向于投“一只虫子”的票,因为最不令人惊讶的原则。人们期望
x[0].extend(y)
的行为类似于
a=x[0];a、 扩展(y)
使其行为类似于
a=x[0];a+=y
的行为类似于
x[0]+=y

如果
self[k]是v
,则可能需要一个可能的修复(至少对于python内置类型而言)将
\uuuuu setitem\uuuuu(self,k,v)
转换为no op。(和覆盖
\uuuu setitem\uuuuu
的自定义类应该遵守)。

有趣的一点

它这样做的原因是

x[0]+=[2,3]
转化为

x[0] = x[0].__iadd__([2,3])
这意味着它首先调用
\uuuu iadd\uuuu
,修改列表,然后才尝试对元组执行非法赋值

(当然,解决问题很容易(例如@luispedro的答案),但我知道你的问题不是如何解决问题。)

它是一个bug、特性还是一个PEP

In [6]: x=([1],)
In [7]: type(x)
Out[7]: tuple
In [8]: x[0]+=[2,3]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-8-a73186f99454> in <module>()
----> 1 x[0]+=[2,3]

TypeError: 'tuple' object does not support item assignment   
In [9]: x
Out[9]: ([1, 2, 3],)
很难说。我倾向于投“一只虫子”的票,因为最不令人惊讶的原则。人们期望
x[0].extend(y)
的行为类似于
a=x[0];a、 扩展(y)
使其行为类似于
a=x[0];a+=y
的行为类似于
x[0]+=y



如果
self[k]是v
,则可能需要一个可能的修复(至少对于python内置类型而言)将
\uuuuu setitem\uuuuu(self,k,v)
转换为no op。(和重写
\uuuu setitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。如何查看列表的代码。uuuIdd_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。这是无法挽回的。只有这样它才能执行
\uuuuu setitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu.尽管出现异常,我仍然不知道初始引用是如何更改的。如何查看列表的代码。uuuIdd_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。这是无法挽回的。只有这样它才能执行
\uuuuu setitem\uuuuuu
赋值,这会导致错误。@shx2解释得很好,但投票给“bug”在我看来并不合适。这只是它的工作方式。@shx2:明白了,谢谢,如果我能投票给它,那就是答案。我的观点是,尽管抛出了异常,但不可变对象还是会被更改。在我的示例中,您可能不希望不可变对象被更改,而是它的一个(可变)成员被更改。这是一个区别。是的,当试图更改不可变对象内的引用时,会引发异常,请参见下文。我的观点是,尽管引发了异常,但不可变对象会发生更改。在我的示例中,您可能不希望不可变对象被更改,而是它的一个(可变)成员被更改。这是一个区别。是的,当试图更改不可变对象中的引用时会引发异常,请参见下文。您不是第一个!还要注意,要使元组可散列,它的所有组件都必须可散列<代码>散列((1,2,3))
工作正常<代码>哈希(([],[],[])
将引发异常。您不是第一个!还要注意,要使元组可散列,它的所有组件都必须可散列<代码>散列((1,2,3))工作正常<代码>哈希(([],[],[])将引发异常。