Python开发中的十大“天坑”,快来看看你是否已经掉坑里?
对于Python这门编程语言,想必大家都很熟悉。Python相较于其他语言,非常的简单易上手,而且很快就能写出很多的程序。但是Python虽然简单,但是老司机们还是会在编程的路上“翻车”。今天,博主就带领大家来看一下,十个Python老手们最容易掉进去的“坑”。
1.is 和 ==的区别
对于is和==的区别,是大家最容易忽视,也最容易犯错的地方之一。
![](https://pic1.zhimg.com/v2-f2ff24e8f89ac4839761a9a3f21c7870_b.png)
如何避免这个错误呢?大家只需要牢牢的记在心里一句话“is比较的是id是不是一样,==比较的是值是不是一样”。
id指的是对象的地址,而值就是指对象的数值。这句话就很方便的让大家在使用is和==上做出区别,从上图的结果中可以看出,a、b、c、的值都是1,但是a和b的id是一样的,而a和c的id是不同的,所以a is b 返回的是True,而a is c返回的是False。
2.Python参数传递是值传递还是引用传递
![](https://pic4.zhimg.com/v2-1da016dc8793bb61eb38ccbc5750ec7b_b.png)
上图可以看出,对于不可变的参数类型,例如字符串、整数这样的类型,函数通过拷贝进行传递,因为函数内外的string变量的id是不一样的。而对于像是列表,字典这样的可变对象,函数是通过引用进行传递。表现在函数内外,列表的id是一样的。
3.函数的返回值
![](https://pic1.zhimg.com/v2-40fce509dcc6af50b8732748e0359ab4_b.png)
当在 "try...finally" 语句的 try 中执行 return, break 或 continue 后, finally 依然会执行。而在Python的函数中,函数的返回值由最后执行的 return 语句决定。
所以函数中使用 "try...finally" 最后的返回结果一定是finally执行的结果。如果大家不想要纸样的话,可以去除finally,但是这样的话,程序的鲁棒性可能会存在问题。
俗话说得好实践出真知,这里给大家推荐一套《2020年最新Python企业级项目开发实战案例》,现在这套是实战案例是免费领取的,点击免费领取即可领取下载。
4.变量值的修改
我们先来看一段程序:
![](https://pic4.zhimg.com/v2-366c85483c22b40c4f368a8717ffa843_b.jpeg)
上图程序中,我们创建了一个二维矩阵matrix,只是想去修改matrix【0】【0】元素,但是结果却是第一行全部被修改了。这是什么原因呢,如下图所示:
![](https://pic3.zhimg.com/v2-465a047c00ce0f38f9a8f5b9457c55ea_b.png)
当我们利用乘法的形式来创建matrix时,matrix[0]、matrix[1]和matrix[2]都指向了sublist的地址。所以当我们修改matrix[0]时,matrix[1]和matrix[2]的值也对应着改变。我们可以通过下述的程序进行修改。
![](https://pic2.zhimg.com/v2-2163b9d7751ced00e95f7f21c41f7b5d_b.png)
5.深拷贝,浅拷贝
对于深拷贝和浅拷贝的考察,是Python面试题中经常会被问到的问题,而且在日常的工作中,也会经常掉进这个坑里。对于浅拷贝就是对于一个对象引用的拷贝,而深拷贝就是对对象资源的拷贝。
此外,对于不可变对象(字符串、元组,整型)的修改,需要开辟新的空间,而对于可变对象(列表,字典等)的修改,不需要开辟新的空间。
![](https://pic4.zhimg.com/v2-0a6dad4828de4912b46f277848cd684b_b.png)
上图左侧我们可以看出,浅拷贝后的orilist和copylist中的元素都指向了相同的地址。我们修改不可变对象的时候,就需要开辟新的空间,所以orilist和copylist中的字符串内容不一样。
但是对于list,修改orilist中的list对象后,copylist中的list内容也随之发生了改变。对于深拷贝,上图右侧结果可以看出,无论是对于可变对象还是不可变对象,对于orilist的修改都不会影响到deepcopylist中的内容。
6. staticmethod 和classmethod
对于Python的面向对象编程时,大家经常会见到被staticmethod 和classmethod装饰的函数。
![](https://pic4.zhimg.com/v2-c127d9e3c8277a1d0e2d3c04e138f973_b.png)
对于classmethod,被成为类方法,第一个参数必须是cls,表示这个类的本身,类方法在调用时,推荐使用类名直接调用,而不是先创建一个类对象后调用。
而对于staticmethod,静态方法,其实就是我们学过的普通函数,静态方法没有类似 self、cls 这样的特殊参数,因此 Python 解释器不会对静态方法中包含的参数做任何类或对象的绑定,所以类的静态方法中无法调用任何类属性和类方法。
对于类的静态方法,可以直接使用类名调用或者创建类对象来进行调用。
7.全局变量的引用
对于在函数中调用全局变量,Python中需要使用关键字 global。但是需要注意的是,在主函数中 ,不需要利用global关键字。
![](https://pic1.zhimg.com/v2-868a30152636860aa345d410a1d26558_b.png)
8.循环变量泄露
上图我们可以看到当我们在全局变量和局部变量中都使用相同的变量名字x的时候,当局部循环结束后,再使用全局变量的x时,数值变成了6而不是4,这是因为在Python中, for 循环作用域在结束后会保留定义的循环变量。
如果我们曾在全局命名空间中定义过循环变量. 在这种情况下, 它会重新绑定现有变量。所以为了避免这种问题,要谨慎的在全局变量和局部变量中使用相同的变量名。
9.del remove pop的区别
对于列表中数据的删除,大家可能都对del、remove 和pop有印象,但是它们之间的区别是什么呢?
pop 接受的是元素的下标,在原列表中删除这个元素,并返回删除的元素。而remove是接受元素的值,在原列表中删除这个元素,但是不返回这个值。
而del是个语句,可以直接销毁掉mylist[0]这个元素,同时del mylist可以销毁整个mylist的列表。同时del的删除操作要比pop和remove要快。
10.操作符的优先级
对于操作符的优先级需要我们有很好的把握。如下图所示:
![](https://pic1.zhimg.com/v2-948591b1b588cec3cf1a94d1d4c841bc_b.png)
我们想判断一下,a、b和c中是否一个至少为3。但是如果按照最上面的程序来写,程序便会报错,原因是“==”的优先级大于“or"。所以判断条件就变为了if (a) or (b) or(c==3)。这样的话,就与我们开始的设想不一样了。所以我们需要将程序按照下面的条件来写,分别将a、b和c与3进行判断。得到正确的判断结果。
总结
以上就是博主今天带领大家复习的十个Python常见的“坑”,并对其进行了一一的分析和解释。欢迎大家在留言区点评,曾经你跨过山河大海,又遇到过几个坑?
另外我建立了一个Python学习圈子,点我就可以加入。在彼此的沟通可以我们可以得到很多学习经验,积累知识,群内有很多有意思的脚本和库,还有2020最新的python学习资料分享,大家可以一起讨论问题,共同进步。