专栏名称: Python学习交流
每天更新,更新python相关的知识。希望诸君有所收获!
目录
相关文章推荐
Python爱好者社区  ·  热议:为什么 DeepSeek ... ·  2 天前  
Python开发者  ·  个人公积金交3998,单位交3998,加起来 ... ·  昨天  
Python中文社区  ·  新龙出现,干它 ·  3 天前  
Python爱好者社区  ·  我???这就是信息差吗?F12改成绩,19. ... ·  3 天前  
Python爱好者社区  ·  两天私活,5w到手 ·  4 天前  
51好读  ›  专栏  ›  Python学习交流

Python 源码理解: '+=' 和 'xx = xx + xx' 的区别

Python学习交流  · 公众号  · Python  · 2017-08-07 23:36

正文

前菜

在我们使用Python的过程, 很多时候会用到 + 运算, 例如:

不光在加法中使用, 在字符串的拼接也同样发挥这重要的作用, 例如:


同样的, 在列表中也能使用, 例如:

为什么上面不同的对象执行同一个 + 会有不同的效果呢? 这就涉及到 + 的重载, 然而这不是本文要讨论的重点, 上面的只是前菜而已~~~


正文

先看一个例子:

这段代码的用途很明确, 就是一个简单的数字相加, 但是这样似乎很繁琐, 一点都Pythonic, 于是就有了下面的代码:

这样就很Pythonic了! 但是这种用法真的就是这么好么? 不一定. 看例子:

看起来结果都一样嘛~, 但是真的一样吗? 我们改下代码再看下:

看到结果了吗? 虽然结果一样, 但是通过 id 的值表示, 运算前后, 第一种方法对象是不同的了, 而第二种还是同一个对象! 为什么会这样?

结果分析

先来看看字节码:

在上诉的字节码, 我们着重需要看的是两个: BINARY_ADD INPLACE_ADD !

很明显:
l = l + [3, 4, 5] 这种背后就是 BINARY_ADD
l += [3, 4, 5] 这种背后就是 INPLACE_ADD

深入理解

虽然两个单词差很远, 但其实两个的作用是很类似的, 最起码前面一部分是, 为什么这样说, 请看源码:

从上面可以看出, 不管是 BINARY_ADD 还是 INPLACE_ADD , 他们都会有如下相同的操作:

1、检查是不是都是 ` int ` 类型 , 如果是 , 直接返回两个数值相加的结果

2、检查是不是都是 ` string ` 类型 , 如果是 , 直接返回字符串拼接的结果

因为两者的行为真的很类似, 所以在这着重讲 INPLACE_ADD , BINARY_ADD 感兴趣的童鞋可以在源码文件: abstract.c , 搜索: PyNumber_Add . 实际上也就少了对列表之类对象的操作而已.

那我们接着继续, 先贴个源码:

INPLACE_ADD 本质上是对应着 abstract.c 文件里面的 PyNumber_InPlaceAdd 函数, 在这个函数中, 首先调用 binary_iop1 函数, 然后进而又调用了里面的 binary_op1 函数, 这两个函数很大一个篇幅, 都是针对 ob_type->tp_as_number , 而我们目前是 list , 所以他们的大部分操作, 都和我们的无关. 正因为无关, 所以这两函数调用最后, 直接返回 Py_NotImplemented , 而这个是用来干嘛, 这个有大作用, 是列表相加的核心所在!

因为 binary_iop1 的调用结果是 Py_NotImplemented , 所以下面的判断成立, 开始寻找对象 ( 也就是演示代码中l对象 ) ob_type->tp_as_sequence 属性.

因为我们的对象是l(列表), 所以我们需要去 PyList_type 需找真相:

可以看出, 其实也就是直接取 list_as_sequence , 而这个是什么呢? 其实是一个结构体, 里面存放了列表的部分功能函数.

接下来就是一个判断, 判断咱们这个 l 对象是否有







请到「今天看啥」查看全文