大家好,我是 Rocky0429,一个正在学习 Python 的蒟蒻…

在学习 Python 的过程中,我为它的简洁优雅而痴迷,但它又是如此的调皮,在提供了很多舒服的功能特性之外,又悄悄挖了很多带有迷惑性的坑,令人防不胜防…

人不能两次踏入同一条河流,在无数次踩进同样的坑里之后,我觉得我有必要整理一下,一为自警,二为给大家提个醒,希望你不要和我犯相同的错误。

这会是一个系列,每篇 5 个,系列文章更新不定,不想错过的,记得点个关注,不迷路。

0x00 走丢的外部变量

首先我们先来看这么一个例子:

e = 429try:raise Exception()
except Exception as e:passprint(e)

PS:except Exception as e 可以捕获除了与程序退出(sys.exit())相关之外的所有异常。

在继续向下看之前,你可以先思考一下上述例子可能出现的结果是什么,也可以自己尝试着在编译器里输入一下。思考完了请继续往下看。

出现的结果如下:

Traceback (most recent call last):File "test.py", line 8, in <module>print(e)
NameError: name 'e' is not defined

竟然报错了,那么这到底是为什么呢?

其实这是因为在 Python3 中使用 as 分配异常的时候,在 except 的末尾将会把这个异常清除掉(在 Python2 中则不会出现这样的情况)。这就好像将上面的示例变成下面的样子:

e = 429try:raise Exception()
except Exception as e:try:passfinally:del eprint(e)

通过上面的变形代码,我们可以很清楚的看明白发生这一切的根源是什么:因为 e 被删除了。这也变相的告诉我们,如果想要在 except 后面引用 e,必须将它先赋值给其它变量。

这样看来,是变量 e 执行了 except 子句而被删除,但是为什么 e 会去执行 except 子句呢?仅仅是因为 e 和 as 后面的 e 长的一毛一样?

答案是否定的,其实这个是因为子句在 Python 中没有独立的作用域,所以上述示例中的所有内容都处于同一个作用域里,所以变量 e 会因为执行了 except 子句而被删除。

0x01 同样是加,却不一定等价

在我们来表示「加」这个概念的时候,一般我们会用两种方式:a = a + b或者是 a += b 。在很多人的概念里这两个其实就是一种,不分彼此,比如之前我就是这么认为的,直到有一天有人拿着下面的坑过来让我踩...

首先我们先来看第一个例子:

>>> a = [1,2,3]
>>> b = a
>>> a = a + [4,5,6]

一个很简单的例子,你知道此时的 a 和 b 分别是多少么?请先自己思考一下再继续向下看:

>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3]

估计很多人都会答对,表达式 a = a + [4,5,6] ,等号右边其实是形成了一个新的列表,最后让 a 引用了这个新的列表,而 b = a 引用的是之前的 a,所以 b 保持不变。

明白了上面的例子,我们接下来再看一个稍微有点区别的例子:

>>> a = [1,2,3]
>>> b = a
>>> a += [4,5,6]

上面的例子和文章开头的例子区别在从 + 变成了 +=,按照我们惯性思维去想,肯定以为这俩例子就是一个东西的两种不同写法而已,可实际上真的是这样吗?让我们来看一下此时的 a,b:

>>> a
[1, 2, 3, 4, 5, 6]
>>> b
[1, 2, 3, 4, 5, 6]

咦?同样是印象里的「加」,好像真的哪里有点不一样诶。。

通过上面我们就可以看出 a = a + b 和 a += b 并不总是表现相同,起码在列表上就是这么表现的。在这里的 a += [4,5,6] 实际上使用的是 extend 函数,所以 a 和 b 仍然指向已被修改的同一列表。

既然在这里说到了 + 和 +=,索性再多补充一点:在使用「加」的概念来连接字符串的时候,+= 其实比 + 的速度更快。

下面我们来实际的演示一下用 + 连接三个字符串:

>>> import timeit
>>> timeit.timeit("a = a + b + c", setup="a='a'*10000;b='b'*10000;c='c'*10000",number=100)
0.07921688999340404
>>> timeit.timeit("a += b + c", setup="a='a'*10000;b='b'*10000;c='c'*10000",number=100)
0.002059974998701364

上面的两个结果很容易看出来,在处理速度上,+= 比 + 处理的速度要快的多。出现这样现象的原因是 += 执行的是追加操作,追加操作的话就会比 + 少了一个销毁然后新建的动作,比如在 a += b + c 上 a 就不会被销毁。

0x02 不一般的小括号

很多学过别的编程语言的同学,很容易会忽略小括号 “()” 在 Python 中的一个重要表现,那就是小括号还能表示“元组” 这一不可变数据类型。

>>> type(())
<class 'tuple'>
>>> tur = (1, 2)
>>> type(tur)
<class 'tuple'>

但是如果小括号内只有一个元素的话,比如像下面这样,它就是小括号内的元素类型:

>>> tur = (1)
>>> type(tur)
<class 'int'>

天呐个天...

那么如果想要表示一个元素的元组咋整呢?要像下面这样:

>>> tur = (1, )
>>> type(tur)
<class 'tuple'>

加个逗号 “,” 就 ok 啦...

0x03 列表的删除没有那么简单

假如我们有一个列表,我想删除列表中的元素:

>>> lst = [1, 2, 3, 4, 5]
>>> for i in lst:
... lst.remove(i)

在刚开始学习 Python 之初,这是很多同学容易想到的做法,然而我们来看一下程序运行完以后的结果:

>>> lst
[2, 4]

看到这个结果,我...

这是为啥子呢?是因为在 for 循环中,如果我们删除了 index = 0 (即 1)的值,原本 index = 1 及其之后的值会向前补位,所以当前 index = 1 的值为之前 index = 2 的值。

列表的删除操作我们经常要用,所以大家要打起十二分的精神来对它。

0x04 is not 不分家

is not 在 Python 中是一伙的,用的时候要靠在一起,分开以后就是两个东西,结果会不一样…

>>> [1, 2, 3] is not None
True
>>> [1, 2, 3] is (not None)
False

这就在于,is not 是个单独的二元运算符,当它两侧的变量指向同一个对象的时候,结果为 False,否则结果为 True,希望引起大家的注意...

❤️ 看完有所收获?希望爱学习的你不要吝啬三连击哟[点赞 + 收藏 + 评论]~

另外本蒟蒻把公众号的高分原创文章整理成了一本电子书,取名《Python修炼之道》,一共 400 页!

具体内容请戳:熬夜爆肝整理 400 页 《Python 修炼之道》,一本高分原创高清电子书送给你!

目录如下:

现在免费送给大家,在我的公众号Python空间(微信搜 Devtogether) 回复 修炼之道即可获取。

作者Info:

【作者】:Rocky0429
【原创公众号】:Python空间。
【简介】:CSDN 博客专家, 985 计算机在读研究生,ACM 退役狗 & 亚洲区域赛银奖划水选手。这是一个坚持原创的技术公众号,专注Python 编程,每天坚持推送各种 Python 基础/进阶文章,数据分析,爬虫实战,数据结构与算法,不定期分享各类资源。
【转载说明】:转载请说明出处,谢谢合作!~

Python 中那些令人防不胜防的坑(一)相关推荐

  1. python中json.dumps使用的坑以及字符编码

    我们知道,python中的字符串分普通字符串和unicode字符串,一般从数据库中读取的字符串会自动被转换为unicode字符串 下面回到重点,使用json.dumps时,一般的用法为: >&g ...

  2. Python 中非常狗的一个坑(在 `a={1:2},`后面多了一个逗号,自动被判为 tuple 类型了)

    本意是好的,语法灵活一点,随意一点,用起来方便. 可是不限制声明类型,甚至元组的声明都不用加括号,这就有点狗了. a = {'a': 2} # a 是 dict a['a'] # a['a'] 是 2 ...

  3. python中var是什么变量_一、 Python概述、变量

    一.        Python概述 1.python是一门面向对象,解释型的脚本语言.语法简洁,编写效率高,但是执行(底层运行)效率低(总的来说解释语言执行效率低于编译语言). 注意:本博客所有的代 ...

  4. python显示3位数不够0补位_关于Python开发中的那些坑总结,令人防不胜防,建议收藏!...

    在学习 Python 的过程中,我为它的简洁优雅而痴迷,但它又是如此的调皮,在提供了很多舒服的功能特性之外,又悄悄挖了很多带有迷惑性的坑,令人防不胜防- 人不能两次踏入同一条河流,在无数次踩进同样的坑 ...

  5. 原创关于python中的一些坑点

    一.range ().map().filter(). dict.items()在python2.7返回列表,而在3.x中返回迭代器.当然迭代器大多数都是比较好的选择,更加pythonic,但是也有缺点 ...

  6. 正确姿势避坑 Python 中的6个典型错误

    点击关注我哦 一篇文章带你使用正确姿势避坑 Python 中的6个典型错误 Python是一种高级的动态脚本语言.它易于使用的特性使得它非常流行,并且在最近几年得到了扩展.易用性也从易滥用开始.我们列 ...

  7. python中拼接路径os.path.join的坑

    1.第一个坑 python中os.path.join的用法如下: import osos.path.join('path1', 'path2', 'pathn') 可以将多个路径进行拼接,但是需要注意 ...

  8. python工程师薪资坑吗-Python中反人类直觉的特性,你踩过坑吗?

    Python是一个基于C语言实现的解释型高级语言, 提供了很多舒适的功能特性,使用起来非常方便.但有的时候, Python的输出结果,让我们感觉一头雾水,其中原因自然是Python语言内部实现导致的, ...

  9. 初学者都在坑里!不要在Python中使用“+”来连接字符串

    很多初学者都像我一样,最开始使用Python时,会不自觉地使用"+"来连接字符串,就像在许多其他编程语言(比如Java)中那样,因为这样既直观又容易. 很多人学习python,不知 ...

  10. python中pymysql的小坑

    python中pymyql的版本 这个版本跟0.9相差比较大,首先你执行完sql语句之后,一定进行commit提交 # 示例代码 cur = self.con.cursor() res = cur.e ...

最新文章

  1. 查询页面代码运行时间
  2. Nginx配置https,反向代理多实例tomcat的操作记录
  3. ASP调用存储过程详解。
  4. Get SQL String From Query Object In Entity Framework
  5. Silverlight WCF 上传实现
  6. Spark SQL程序操作HiveContext
  7. 快学Scala 第二课 (apply, if表达式,循环,函数的带名参数,可变长参数,异常)...
  8. 什么是中国1号信令?
  9. 通过使用CSS字体阴影效果解决hover图片时显示文字看不清的问题
  10. dj打碟怎么学_学DJ打碟 - Rane声卡连接
  11. Mysql(三)——(cmd)数据库的命令操作
  12. 【XXE】XXE漏洞攻击与防御
  13. Process打开文件
  14. 【leetcode】复写零
  15. 【Python】32 个常用入门 Python 实现
  16. [HNOI2010]PLANAR
  17. 使用ildasm反编译修改c# dll
  18. 向量的方向余弦公式_方向余弦怎么求
  19. 计算噪声方差的函数 matlab,噪声强度(噪声功率) 噪声方差到底有什么关系? matlab中的awgn函数...
  20. 单反相机参数之光圈、快门篇

热门文章

  1. 万网域名修改 DNS 方法
  2. PQ 8.05中文版硬盘物理分区与删除分区(图文详解)
  3. 【权益证明与错误的工程学思维模式】PoS正驶向错误的方向:是在降低而不是提升质量....
  4. elementUI的tree组件搜索过滤,可识别拼音,且不区分大小写
  5. Bugly热更新最详细的使用教程
  6. 转 OpenGL核心技术之帧缓冲
  7. 搭建表白网站详细教程,小白也可以学懂!!!!
  8. ubuntu 装机必备软件
  9. 计算机蓝屏解决,电脑蓝屏怎么解决,详细解决蓝屏方案
  10. Android加载服务器的静态图片文件