第四章 操作列表
切片也是对象,中括号则是列表的特殊方法
切片是 python 的一种高级特性,通过它能够方便的对列表实现复杂的子列选取。虽然切片看上去是一种特别语法,但其实,切片本身也是一个对象操作。python 中有一个内置函数叫做 slice,当你使用如上的切片语法时,其实等同于你使用了一个 slice 函数生成一个切片对象。什么意思呢?
所以如同三大定理第一条,python 中的一切皆是对象。列表是对象,切片也是对象。列表的切片操作其实是在调用列表的内置特殊方法__getitem__()
,该方法接受一个切片对象作为参数,以此选择并返回列表中的对应元素。当然,实际情况中,你依然应该用切片语法list[start:end:step]
来进行切片操作,但通过上述解释,我们可以明白 python 中的很多特殊语法,其实只是基于 python 对象操作的简写!
万变不离其宗。
迭代
python中,许多类型都可以直接通过 for 循环进行迭代,比如列表和字符串。如果 python 是你学习的第一门编程语言,你可能不会觉得这有什么特殊的,但这其实是一个很酷的特性。如果你简单了解一下 c 语言中类似的循环,你就会发现,为什么我们说 python 是一门简洁易读,新手友好的语言。
但同时,不是所有的类型都可以通过 for 语句循环遍历的,比如说 int 就不行
如何解释 int 为什么不可以迭代呢?是因为会产生歧义吗?比如到底是迭代从 1-123 的所有数字,还是迭代 int 中出现的每一个字符(就和迭代 str 一样)呢?
其实,要理解深层次的原因,我们又要再次回到 python 中的对象及其方法这一基本定理来。上一节我们提到 python 中的很多特殊语法,其实只是基于 python 对象操作的简写。比如包在切片语法外围的中括号,其实就是调用 python 列表对象的__getitem__()
方法,而 for 循环也是这样!当你通过 for 循环语句去试图迭代一个对象时,其实 python 在内部调用了该对象的__iter__()
方法,iter 就是 iteration 的简写,只有当一个类型有__iter__()
方法时,它才可能被 for 循环遍历,而当它没有__iter__()
方法时,自然也就会产生不可迭代的错误了。
通过hasattr() 函数,我们可以证明这一点。这个内置函数能够让我们通过名称确认某个类型是否具有同名方法:
小问题:既然 int 不可循环,那我们怎么实现用 for 循环 1 - 123 的每一个整数呢?
列表拆分
考虑下面这样一个需求:
小学生写法
大学生写法
这里,我们就用到了列表拆分(unpack)。当一个表达式左边有多个变量,而右边是一个可迭代(根据上面的解释,也就是有__iter__()
方法)的对象时,python 就会自动拆分这个可迭代对象。但因为左边对象与右边元素数量不相等,我们就需要通过星号表达式(starred expression)来匹配中间的对象。上面这句语句的意思是,第一个和第三个变量只接受列表的第一个和最后一个元素,而中间带星号的变量接受所有其他元素(0 到任意数量个,并且中间变量始终为列表)
星号表达式很重要,你知道这个名词之后,可以通过 google 学到更多细节。或者,就留个印象也是很好的,因为在函数章节我们还要提到它。
介绍一下列表推导式和 zip()
zip()
考虑下面这样一个需求:
小学生
中学生
zip 就是拉链,顾名思义,这个函数能够像拉链一样把两个列表一一对应起来,我们就不需要专门生成一个位置变量,而可以直接迭代他们的值了
大学生
上面给 c 赋值的这个语法叫做列表推导式(list comprehension),它和第二种语法做的事情一模一样,只不过把生成列表与循环向列表赋值放在了一行里面完成!我们将在下一章结合 if 详细讨论列表推导式。但是这里,你可以看到,同一件事情,其实有很多不同的方式去完成。一般来说,我们都喜欢最简洁和优美的写法,也就是第三种!
学习建议:正确的名词 + Google 是最好的学习方式
很多时候,只要知道一个名词,剩下的事情,请教 google 就可以了!这里限于篇幅(懒),我没有详细展开上面提到的诸多名词,但既然你知道他们大概是什么了,你可以轻而易举的从 google 中获取更多他们的说明,以及精心设计的案例!
列表拆分(unpack)
星号表达式(starred expression)
对象的内置方法是许多语法形式的本质(如
__iter__()
),内置方法也叫魔法方法(magic methods, python 的魔力来源!) ,这是个很大的话题,有一本叫做 fluent python 的进阶书籍对我帮助很大!但这本书不太适合刚刚接触 python 的新手。列表推导式(list comprehension)
这些内容不仅仅是看上去简洁优美的奇技淫巧而已,在深入学习他们的过程中,我们也更能了解 python 的许多深刻特性(三大定理)。这对于理解后面的很多内容都是大有裨益的。
比如,星号表达式就会在函数参数传递中再次讲到,可迭代对象也不仅仅有列表和字符串,你在后面遇到的绝大多数数据结构,都是某种程度可迭代的,他们在被迭代时行为是通过各自独特的__iter__()
方法来实现的,所以各不相同!
最后更新于