• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

python为什么 a_tuple[i] += [item] 会在执行加法时引发异常?

python 搞java代码 3年前 (2022-05-21) 33次浏览 已收录 0个评论

这是由两个事实共同导致的结果,一是增强赋值运算符属于 赋值 运算符,二是在 Python 中存在可变和不可变两种不同的对象。

此处的讨论在任何对元组中指向可变对象的元素使用增强赋值运算符的情况都是普遍成立的,但在此我们只以 list+= 来举例。

如果你写成这样:

>>>

<span class="gp">>>> </span><span class="n">a_<a href="https://www.gaodaima.com/tag/tuple" title="查看更多关于tuple的文章" target="_blank">tuple</a></span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="gp">>>> </span><span class="n">a_tuple</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="gt">Traceback (most recent call last):</span>
   <span class="c">...</span>
<span class="gr">TypeError</span><span>: </span><span class="n">"tuple" object does not support <a href="https://www.gaodaima.com/tag/item" title="查看更多关于item的文章" target="_blank">item</a> assignment</span>

www#gaodaima.com来源gao!daima.com搞$代!码网搞代码

发生异常的原因是显而易见的: 1 会与对象 a_tuple[0] 相加,而该对象为 (1),得到结果对象 2,但当我们试图将运算结果 2 赋值给元组的 0 号元素时就将报错,因为我们不能改变元组的元素所指向的对象。

在表层之处,以上增强赋值语句所做的大致是这样:

>>>

<span class="gp">>>> </span><span class="n">result</span> <span class="o">=</span> <span class="n">a_tuple</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span>
<span class="gp">>>> </span><span class="n">a_tuple</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span>
<span class="gt">Traceback (most recent call last):</span>
  <span class="c">...</span>
<span class="gr">TypeError</span><span>: </span><span class="n">"tuple" object does not support item assignment</span>

由于元组是不可变的,因此操作的赋值部分会引发错误。

当你这样写的时候:

>>>

<span class="gp">>>> </span><span class="n">a_tuple</span> <span class="o">=</span> <span class="p">([</span><span class="s1">"foo"</span><span class="p">],</span> <span class="s1">"bar"</span><span class="p">)</span>
<span class="gp">>>> </span><span class="n">a_tuple</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="p">[</span><span class="s1">"item"</span><span class="p">]</span>
<span class="gt">Traceback (most recent call last):</span>
  <span class="c">...</span>
<span class="gr">TypeError</span><span>: </span><span class="n">"tuple" object does not support item assignment</span>

发生异常会令人略感吃惊,还有一个更为令人吃惊的事实:虽然有报错,但是添加操作却生效了:

>>>

<span class="gp">>>> </span><span class="n">a_tuple</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="go">["foo", "item"]</span>

要明白为何会这样,你需要知道 (a) 如果一个对象实现了 __iadd__ 魔术方法,它会在执行 += 增强赋值时被调用,并且其返回值将用于该赋值语句; (b) 对于列表来说,__iadd__ 等价于在列表上调用 extend 并返回该列表。 因此对于列表我们可以说 += 就是 list.extend 的“快捷方式”:

>>>

<span class="gp">>>> </span><span class="n">a_list</span> <span class="o">=</span> <span class="p">[]</span>
<span class="gp">>>> </span><span class="n">a_list</span> <span class="o">+=</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="gp">>>> </span><span class="n">a_list</span>
<span class="go">[1]</span>

这相当于:

>>>

<span class="gp">>>> </span><span class="n">result</span> <span class="o">=</span> <span class="n">a_list</span><span class="o">.</span><span class="fm">__iadd__</span><span class="p">([</span><span class="mi">1</span><span class="p">])</span>
<span class="gp">>>> </span><span class="n">a_list</span> <span class="o">=</span> <span class="n">result</span>

a_list 所引用的对象已被修改,而引用被修改对象的指针又重新被赋值给 a_list。 赋值的最终结果没有变化,因为它是引用 a_list 之前所引用的同一对象的指针,但仍然发生了赋值操作。

因此,在我们的元组示例中,发生的事情等同于:

>>>

<span class="gp">>>> </span><span class="n">result</span> <span class="o">=</span> <span class="n">a_tuple</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="fm">__iadd__</span><span class="p">([</span><span class="s1">"item"</span><span class="p">])</span>
<span class="gp">>>> </span><span class="n">a_tuple</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span>
<span class="gt">Traceback (most recent call last):</span>
  <span class="c">...</span>
<span class="gr">TypeError</span><span>: </span><span class="n">"tuple" object does not support item assignment</span>

__iadd__ 成功执行,因此列表得到了扩充,但是虽然 result 指向了 a_tuple[0] 已经指向的同一对象,最后的赋值仍然导致了报错,因为元组是不可变的。

来源:搞代码网:原文地址:https://www.gaodaima.com


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:python为什么 a_tuple[i] += [item] 会在执行加法时引发异常?

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址