时间:2021-05-22
Python是一门清晰简洁的语言,如果你对一些细节不了解的话,就会掉入到那些深不见底的“坑”里,下面,我就来总结一些Python里常见的坑。
列表创建和引用
嵌套列表的创建
使用*号来创建一个嵌套的list:
li = [[]] * 3 print(li) # Out: [[], [], []]通过这个方法,可以得到一个包含3个list的嵌套list,我们来给第一个list增加一个元素:
li[0].append(1) print(li) # Out: [[1], [1], [1]]通过输出的结果可以看初,我们只给第一元素增加元素,结果三个list都增加了一个元素。这是因为[[]]*3并不是创建了三个不同list,而是创建了三个指向同一个list的对象,所以,当我们操作第一个元素时,其他两个元素内容也会发生变化的原因。效果等同于下面这段代码:
li = [] element = [[]] li = element + element + element print(li) # Out: [[], [], []] element.append(1) print(li) # Out: [[1], [1], [1]]我们可以打印出元素的内存地址一探究竟:
li = [[]] * 3 print([id(inner_list) for inner_list in li]) # Out: [6830760, 6830760, 6830760]到这我们可以明白原因了。那如何解决了?可以这样:
li = [[] for _ in range(3)]这样我们就创建了三个不同的list对象
print([id(inner_list) for inner_list in li]) # Out: [6331048, 6331528, 6331488]列表元素的引用
不要使用索引方法遍历list,例如:
for i in range(len(tab)): print(tab[i])比较好的方法是:
for elem in tab: print(elem)for语句会自动生成一个迭代器。如果你需要索引位置和元素,使用enumerate函数:
for i, elem in enumerate(tab): print((i, elem))注意 == 符号的使用
if (var == True): # 当var是:True、1、 1.0、 1L时if条件成立 if (var != True): # 当var不是 True 和 1 时if条件成立 if (var == False): # 当var是 False 或者 0 (or 0.0, 0L, 0j) if条件成立 if (var == None): # var是None if条件成立 if var: # 当var非空(None或者大小为0)对象 string/list/dictionary/tuple, non-0等if条件成立 if not var: # 当var空(None或者大小为0)对象 string/list/dictionary/tuple, non-0等if条件成立 if var is True: # 只有当var时True时 if条件成立 1也不行 if var is False: # 只有当var时False时 if条件成立 0也不行 if var is None: # 和var == None 一致捕获异常由于提前检查
不够优雅的代码:
if os.path.isfile(file_path): file = open(file_path) else: # do something比较好的做法:
try: file = open(file_path) except OSError as e: # do something在python2.6+的里面可以更简洁:
with open(file_path) as file:之所以这么用,是这么写更加通用,比如file_path给你传个None就瞎了,还得判断是不是None,如果不判断,就又得抓异常,判断的话,代码有多写了很多。
类变量初始化
不要在对象的init函数之外初始化类属性,主要有两个问题
错误示范(除非你想要静态变量)
``` class Car(object): color = "red" wheels = [Wheel(), Wheel(), Wheel(), Wheel()]```正确的做法:
``` class Car(object): def __init__(self): self.color = "red" self.wheels = [Wheel(), Wheel(), Wheel(), Wheel()]```**函数默认参数**```def foo(li=[]): li.append(1) print(li)foo([2])# Out: [2, 1]foo([3])# Out: [3, 1]```该代码的行为与预期的一样,但如果我们不传递参数呢?
```foo()# Out: [1] As expected...foo()# Out: [1, 1] Not as expected...```这是因为函数参数类型是定义是确认的而不是运行时,所以在两次函数调用时,li指向的是同一个list对象,如果要解决这个问题,可以这样:
```def foo(li=None): if not li: li = [] li.append(1) print(li)foo()# Out: [1]foo()# Out: [1]```这虽然解决了上述的问题,但,其他的一些对象,比如零长度的字符串,输出的结果就不是我们想要的。
```x = []foo(li=x)# Out: [1]foo(li="")# Out: [1]foo(li=0) # Out: [1]```最常用的办法是检查参数是不是None
```def foo(li=None): if li is None: li = [] li.append(1) print(li)foo()# Out: [1]```**在遍历时修改**for语句在遍历对象是会生成一个迭代器,如果你在遍历的过程中修改对象,会产生意想不到的结果:
alist = [0, 1, 2] for index, value in enumerate(alist): alist.pop(index) print(alist) # Out: [1]第二个元素没有被删除,因为迭代按顺序遍历索引。上述循环遍历两次,结果如下:
# Iteration #1 index = 0 alist = [0, 1, 2] alist.pop(0) # removes '0' # Iteration #2 index = 1 alist = [1, 2] alist.pop(1) # removes '2' # loop terminates, but alist is not empty: alist = [1]如果避免这个问题了,可以创建另外一个list
alist = [1,2,3,4,5,6,7] for index, item in reversed(list(enumerate(alist))): # delete all even items if item % 2 == 0: alist.pop(index) print(alist) # Out: [1, 3, 5, 7]整数和字符串定义
python预先缓存了一个区间的整数用来减少内存的操作,但也正是如此,有时候会出很奇特的错误,例如:
>>> -8 is (-7 - 1) False >>> -3 is (-2 - 1) True另外一个例子
>>> (255 + 1) is (255 + 1) True >>> (256 + 1) is (256 + 1) False通过不断的测试,会发现(-3,256)这区间的整数都返回True,有的甚至是(-8,257)。默认情况下,[-5,256]会在解释器第一次启动时创建并缓存,所以才会有上面的奇怪的行为。这是个很常见但很容易被忽略的一个坑。解决方案是始终使用equality(==)运算符而不是 identity(is)运算符比较值。
Python还保留对常用字符串的引用,并且可以在比较is字符串的身份(即使用)时产生类似的混淆行为。
>>> 'python' is 'py' + 'thon'Truepython字符串被缓存了,所有python字符串都是该对象的引用,对于不常见的字符串,即使字符串相等,比较身份也会失败。
>>> 'this is not a common string' is 'this is not' + ' a common string'False>>> 'this is not a common string' == 'this is not' + ' a common string'True所以,就像整数规则一样,总是使用equal(==)运算符而不是 identity(is)运算符比较字符串值。
列表推导和循环中的变量泄漏
有个例子:
i = 0 a = [i for i in range(3)] print(i) # Outputs 2python2中列表推导改变了i变量的值,而python3修复了这个问题:
i = 0 a = [i for i in range(3)] print(i) # Outputs 0类似地,for循环对于它们的迭代变量没有私有的作用域
i = 0 for i in range(3): pass print(i) # Outputs 2这种行为发生在Python 2和Python 3中。
为了避免泄漏变量的问题,请在列表推导和for循环中使用新的变量。
or操作符
例如
if a == 3 or b == 3 or c == 3:这个很简单,但是,再看一个:
if a or b or c == 3: # Wrong这是由于or的优先级低于==,所以表达式将被评估为if (a) or (b) or (c == 3):。正确的方法是明确检查所有条件:
if a == 3 or b == 3 or c == 3: # Right Way或者,可以使用内置函数any()代替链接or运算符:
if any([a == 3, b == 3, c == 3]): # Right或者,为了使其更有效率:
更加简短的写法:
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
近几年,移动互联网创业高潮迭起,我们身处这个时代,必要赶上这个浪潮;各行各业的企业都在考虑转型,靠近互联网,拥有自己的APP;殊不知APP开发行业的水深不见底,
“深不见底”的二手手机市场图源:艾媒咨询二手手机成“金矿”,线上平台齐“掘金”“外表光鲜”的背后是致命的黑暗C2C模式弊端尽显,C2B2C才是最终“归宿”?二手
本篇文章介绍了Python中一些常见的包的作用和安装方法,希望对学习Python中的朋友有帮助!Python中一些包的基本用处和安装方法pika可以用来连接Ra
最近有个Python程序需要安装并作为Windows系统服务来运行,过程中碰到一些坑,整理了一下。Python服务类首先Python程序需要调用一些Window
'chromedriver'executableneedstobeinPath声明:本人萌新,刚学python不久记录一下自己的坑,发出来若能帮助到一些人尽早解