Python中的连接符(+、+=)示例详解


Posted in Python onJanuary 13, 2017

前言

本文通过在一段示例代码中发现的问题,来给大家详细介绍了Python中的连接符(+、+=),下面话不多说,来看详细的介绍吧。

假设有下面一段代码:

a = [1, 2, 3, 4]
b = [5, 6, 7, 8, 9]
c = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

for item in (a, b, c):
 item += [0] * (10 - len(item))

print a
print b
print c

这段代码的意思是,有三个列表,需要在长度不为 10 的列表尾部填充 0,让其长度变为10。

输出如下:

[1, 2, 3, 4, 0, 0, 0, 0, 0, 0]
[5, 6, 7, 8, 9, 0, 0, 0, 0, 0]
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

这里没什么问题,一切正常。但是,现在变了需求,需要在长度不为 10 的列表的前面填充 0。

那么,我们尝试做如下的改动:

a = [1, 2, 3, 4]
b = [5, 6, 7, 8, 9]
c = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

for item in (a, b, c):
 item = [0] * (10 - len(item)) + item

print a
print b
print c

直接来看一下输出:

[1, 2, 3, 4]
[5, 6, 7, 8, 9]
[11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

结果却不是我们想象的那样。如果你没有发现问题的所在,就继续往下看吧。当然,如果你已经看出了其中的端倪,那就不需要在这里浪费时间了。

按照我们固有的思维,上面的方法是可行,例如下面的实例:

>>> l = [1, 2, 3, 4, 5]
>>> l = [0]*5 + l
>>> l
[0, 0, 0, 0, 0, 1, 2, 3, 4, 5]

这样的操作让列表如愿以偿的得到我们所期望的改变。

但是,如果我们在其中多加几个步骤呢:

>>> l = [1, 2, 3, 4, 5]
>>> id(l)
139935500860952
>>> l = [0]*5 + l
>>> l
[0, 0, 0, 0, 0, 1, 2, 3, 4, 5]
>>> id(l)
139935500783272

到此,是不是已经看出问题所在了呢。通过 id() 方法的输出可以看到,后边的 “l” 已经不是前边的 “l” 了。

再看看下边的例子:

>>> l = [1, 2, 3, 4, 5]
>>> id(l)
139935500861024
>>> l += [0]*5
>>> l
[1, 2, 3, 4, 5, 0, 0, 0, 0, 0]
>>> id(l)
139935500861024

当用 += 时, “l” 前后是一个。此时,我们应该明白一个事实,文章开头的例子并非莫名其妙,而是有原因的。

别着急,我们再来看看例子:

>>> t = (1, 2, 3, 4, 5)
>>> id(t)
139935501840656
>>> t += (0,)*5
>>> t
(1, 2, 3, 4, 5, 0, 0, 0, 0, 0)
>>> id(t)
139935502151336

可以看到,当我们把列表换成元组时,结果又发生了变化。

那么我们对元组使用 + 操作呢:

>>> t = (1, 2, 3, 4, 5)
>>> id(t)
139935501081200
>>> t = (0,)*5 + t
>>> t
(0, 0, 0, 0, 0, 1, 2, 3, 4, 5)
>>> id(t)
139935502151336

这与列表结果是一样的,没有什么不同。

那么,再来看看字符串呢:

>>> s = "hello"
>>> id(s)
139935500909712
>>> s += "world"
>>> s
'helloworld'
>>> id(s)
139935500909664

结果如同元组,“s” 在使用 += 拼接一个字符串后,被重新赋了值,已然不是之前的变量。反映在内存中就是,“s” 被另外开辟了一个存储空间来存放值。

这里,我们要谈的 Python 连接符就是 + 与 +=。要注意在 Python 中这两个符号有成含义,一个是运用在数学中的加法运算,一个是用在序列类型上的拼接功能。不过,作为加法运算符时,也遵循本文讨论的使用规则。因为讨论这两个符号,本质上是讨论 Python 的 immutable 和 mutable,即可变类型与不可变类型。对可变类型也说,我们可以在原地被变量进行修改,也就是说它的存储空间是可读可写的,例如 list;而对于不可变类型来说,它的存储空间则是只读的,无法对其进行修改,如果需要对不可变类型进行某些操作来得到新的结果,则需要重新开辟一份存储空间来存放这个新产生的结果。

由以上列举的例子,我们可以得到如下的结论:

对于可变类型:

  1. +: 代表连接操作,其结果会创建一个新的对象。
  2. +=: 代表追加操作,即 in-place 操作,在原地把另一个对象的内容追加到对象中。

对于不可变类型: + 与 += 都代表连接或求和操作,两者没有什么区别,其操作的结果都会产生一个新的对象。

下面我们来分析一下文章开头的例子,由于 for 迭代相当于赋值,为了简单起见,我们只分析 a,如下所示:

>>> a = [1, 2, 3, 4]
>>> t = a
>>> id(a)
139712695835400
>>> id(t)
139712695835400
>>> t += [0]*6
>>> t
[1, 2, 3, 4, 0, 0, 0, 0, 0, 0]
>>> id(t)
139712695835400
>>> id(a)
139712695835400
>>> a
[1, 2, 3, 4, 0, 0, 0, 0, 0, 0]
>>>
>>>
>>> a = [1, 2, 3, 4]
>>> t = a
>>> id(a)
139712695835464
>>> id(t)
139712695835464
>>> t = [0]*6 + t
>>> t
[0, 0, 0, 0, 0, 0, 1, 2, 3, 4]
>>> a
[1, 2, 3, 4]
>>> id(a)
139712695835464
>>> id(t)
139712695835400

这里, t 是对 a 的一个引用,就相当于文章开头例子的 item。用 += 对 t 进行操作实际上是对 a 进行操作,而 += 是原地操作,所以改变 t 时,a 也随之变化;如果用 + 对 t 进行操作,在将结果赋值给 t,那么此时的 t 就不再指向 a 了,而是指向 [0]*6 + t,所以 a 没有被改变。

总结

以上就是这篇文章的全部内容了,这里讨论的只是一个简单的问题,而我却用了这么长的篇幅来谈论这个问题,所以我想说的是,对于这些小问题,如果你没有完全理解,那么在程序设计过程中可能会给你带来麻烦。

Python 相关文章推荐
Python 文件操作技巧(File operation) 实例代码分析
Aug 11 Python
Python跳出循环语句continue与break的区别
Aug 25 Python
Python基于scrapy采集数据时使用代理服务器的方法
Apr 16 Python
Python中的ctime()方法使用教程
May 22 Python
python解析xml文件实例分析
May 27 Python
Python3.5编程实现修改IIS WEB.CONFIG的方法示例
Aug 18 Python
Python3操作MongoDB增册改查等方法详解
Feb 10 Python
解决python DataFrame 打印结果不换行问题
Apr 09 Python
解决python运行启动报错问题
Jun 01 Python
导致python中import错误的原因是什么
Jul 01 Python
matplotlib部件之套索Lasso的使用
Feb 24 Python
Python使用DFA算法过滤内容敏感词
Apr 22 Python
Python中datetime模块参考手册
Jan 13 #Python
python 计算文件的md5值实例
Jan 13 #Python
Python 字典与字符串的互转实例
Jan 13 #Python
python 安装virtualenv和virtualenvwrapper的方法
Jan 13 #Python
Python 使用os.remove删除文件夹时报错的解决方法
Jan 13 #Python
python递归删除指定目录及其所有内容的方法
Jan 13 #Python
Python实现二分查找与bisect模块详解
Jan 13 #Python
You might like
php汉字转拼音的示例
2014/02/27 PHP
php生成圆角图片的方法
2015/04/07 PHP
PHP封装返回Ajax字符串和JSON数组的方法
2017/02/17 PHP
Yii实现复选框批量操作实例代码
2017/03/15 PHP
JavaScript入门教程(5) js Screen屏幕对象
2009/01/31 Javascript
JavaScript入门教程(7) History历史对象
2009/01/31 Javascript
解析javascript 数组以及json元素的添加删除
2013/06/26 Javascript
iframe如何动态创建及释放其所占内存
2014/09/03 Javascript
JS中获取函数调用链所有参数的方法
2015/05/07 Javascript
JS模拟酷狗音乐播放器收缩折叠关闭效果代码
2015/10/29 Javascript
jquery购物车结算功能实现方法
2020/10/29 Javascript
根据Bootstrap Paginator改写的js分页插件
2016/12/25 Javascript
Vue-resource实现ajax请求和跨域请求示例
2017/02/23 Javascript
基于JS代码实现简单易用的倒计时 x 天 x 时 x 分 x 秒效果
2017/07/13 Javascript
vue2.0 axios跨域并渲染的问题解决方法
2018/03/08 Javascript
element-ui upload组件多文件上传的示例代码
2018/10/17 Javascript
JointJS JavaScript流程图绘制框架解析
2019/08/15 Javascript
Python中使用glob和rmtree删除目录子目录及所有文件的例子
2014/11/21 Python
玩转python爬虫之cookie使用方法
2016/02/17 Python
Python变量和字符串详解
2017/04/29 Python
Python实现对象转换为xml的方法示例
2017/06/08 Python
Python 异常处理Ⅳ过程图解
2019/10/18 Python
CSS3颜色值RGBA与渐变色使用介绍
2020/03/06 HTML / CSS
蛋白质世界:Protein World
2017/11/23 全球购物
Bluebella德国官网:英国性感内衣和睡衣品牌
2019/11/08 全球购物
请编程遍历页面上所有 TextBox 控件并给它赋值为 string.Empty
2015/12/03 面试题
应届大学生自荐信格式
2013/09/21 职场文书
出国签证在职证明
2014/01/16 职场文书
供货协议书
2014/04/22 职场文书
支行行长竞聘演讲稿
2014/05/15 职场文书
国贸专业毕业求职信
2014/06/11 职场文书
SQL Server 数据库实验课第五周——常用查询条件
2021/04/05 SQL Server
使用pipenv管理python虚拟环境的全过程
2021/09/25 Python
Nginx源码编译安装过程记录
2021/11/17 Servers
python的netCDF4批量处理NC格式文件的操作方法
2022/03/21 Python
Win11 Beta 22621.601 和 22622.601今日发布 KB5017384修复内容汇总
2022/09/23 数码科技