曾经,我被Python这些陷阱坑的找不着北...

来自:Python空间(微信号:Devtogether),作者:Rocky0429



00.写在之前


在我的系列文章 零基础学习 Python 中我介绍完了 Python 的基本对象类型,表面看上去这些东西都很简单,就是看一看背一背敲一敲洒洒水就可以搞定的东西,但是很多时候往往就是这些简单的东西会给你挖个大大的坑,做一点拙劣的掩饰,等着 45 度仰望星空的你蹦蹦跳跳的掉进去。


这一篇文章就让我们来列举一下“简单“的基本对象类型可能会让我们头疼的一些常见问题,顺便讨论一下对于这些问题我们该如何规避解决。可能有的我在以前的文章中已经提到过了,但鉴于它们真的很重要,值得我再一次提到。


01.赋值生成引用


对于这个非常核心的问题,我必须再提及它一次。你需要理解「共享引用」是怎么回事。为了更好的回忆,我们来看一个例子:


>>> lst1 = [1,2,3]
>>> lst2 = ['A','B',lst1]
>>> lst2
['A''B', [123]]
>>> lst1[0] = 0
>>> lst2
['A''B', [023]]


上面例子中赋值给 lst1 的列表对象不但被 lst1 引用,也被赋值为 lst2的内部列表引用,同时在原处修改了 lst1 的同时也修改了 lst2 的引用。这种影响在小的程序中不显山露水,通常正在大型程序中才显得重要,而这里面「共享引用」才是我们真正想要的。


如果你不想对象共享的话,可以对它们先进行拷贝。就上面例子中的列表,你可以对它们进行切片生成一个拷贝:


>>> lst1 = [1,2,3]
>>> lst2 = ['A','B',lst1[:]]
>>> lst1[0] = 0
>>> lst1
[023]
>>> lst2
['A''B', [123]]


上面的切片就是将列表中的每一项抽取出来,生成了一个新的无共享的对象。


02.不可变类型的修改


不可变对象不能在原处修改。如果需要改变的话,我们只能采用迂回战术,通过切片、合并等操作创建一个新的对象,最后再赋值给原引用。具体操作如下所示:


>>> t = (1,2,3)
>>> t[0] = 0
Traceback (most recent call last):
File "<stdin>", line 1in <module>
TypeError: 'tuple' object does not support item assignment
>>> t = (0,)+t[1:]
>>> t
(023)


这样做看起来很不 Pythonist,做了很多多余的工作。但是我们换个角度来看,这样用元组、数字等不可变对象其实是有好处的,因为无法在原处修改,不会出现上一小节中列表 lst1 和 lst2 中出现的那种问题。


03.列表重复


「列表重复」表面上看起来就是自己多次加上自己。这是事实,但是当列表被嵌套的时候产生的效果就不见得是我们想的那样。我们来看下面这个例子:


>>> lst = [1,2,3]
>>> l1 = lst * 3
>>> l2 = [lst] * 3
>>> l1
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> l2
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]


上面 l1 赋值给重复四次的 lst,l2 赋值给包含重复四次 lst的。由于 lst 在 l2 的那行代码中是嵌套的,返回赋值为 lst 的原始列表,所以会出现在「赋值生成引用」这一节中出现的那种问题:


>>> lst[0] = 0
>>> l1
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> l2
[[0, 2, 3], [0, 2, 3], [0, 2, 3]]


解决上面问题和之前我们说过的一样,比如用切片的方法形成一个新的无共享的对象,因为这个的确是以另一种生成共享可变对象的方法。


04.循环对象


「循环对象」就是一个复合对象包含指向自身的引用。无论何时何地 Python 对象中检测到了循环,都会打印成 [...] 的形式,而不是陷入无限循环的境地。我们还是先看一个例子:


>>> lst = ['Rocky']
>>> lst.append(lst)
>>> lst
['Rocky', [...]]


我们除了要知道上面的 [...] 代表对象中带有循环之外,还有一种容易造成误会的情况也该知道:「循环结构可能会导致程序代码陷入到无法预期的循环当中」。


至于这句话我们现在不去细究,你需要知道的是除非你真的需要,否则不要使用循环引用,我相信你肯定不想让自己陷入某些“玄学“的麻烦中。

推荐↓↓↓
Python编程
上一篇:Python在基金定投上的验证 下一篇:直到面试被问到什么是「共享引用」,我才发现对于它的一无所知...