列表类型是一个容器,它里面能够存听任意数量、任意类型的数据。html
例以下面的几个列表中,有存储数值的、字符串的、内嵌列表的。不只如此,还能够存储其余任意类型。python
>>> L = [1, 2, 3, 4] >>> L = ["a", "b", "c", "d"] >>> L = [1, 2, "c", "d"] >>> L = [[1, 2, 3], "a", "b", [4, "c"]]
python中的列表是一个序列,其内元素是按索引顺序进行存储的,能够进行索引取值、切片等操做。shell
列表是可变对象,能够原处修改列表中的元素而不会让列表有任何元数据的变更。app
>>> L = ["a", "b", "c"] >>> id(L), id(L[0]) (57028736, 55712192) >>> L[0] = "aa" >>> id(L), id(L[0]) (57028736, 56954784)
从id的变更上看,修改列表的第一个元素时,列表自己的id没有改变,但列表的第一个元素的id已经改变。函数
看了下面列表的内存图示就很容易理解了。性能
上面是L = ["a", "b", "c"]
列表的图示。变量名L存储了列表的内存地址,列表内部包含了类型声明、列表长度等元数据,还保存了属于列表的3个元素的内存地址。须要注意的是,列表元素不是直接存在列表范围内的,而是以地址的形式保存在列表中。测试
因此,修改列表中的元素时,新建一个元素"aa"(之因此新建,是由于字符串是不可变类型),列表自己并无改变,只是将列表中指向第一个元素的地址改成新数据"aa"的地址。ui
由于修改列表数据不会改变列表自己属性,这种行为称为"原处修改"。code
因此,列表有几个主要的的特性:htm
有两种经常使用的构造列表方式:
[]
使用(中)括号构建列表时,列表的元素能够跨行书写,这是python语法中各类括号类型的特性。
例如:
>>> [] # 空列表 >>> [1,2,3] [1, 2, 3] >>> L = [ 1, 2, 3 ] >>> list('abcde') ['a', 'b', 'c', 'd', 'e'] >>> list(range(0, 4)) [0, 1, 2, 3]
上面range()用于生成一系列数值,就像Linux下的seq命令同样。可是range()不会直接将数据生成出来,它返回的是一个可迭代对象,表示能够一个一个地生成这些数据,因此这里使用list()将range()的数据所有生成出来并造成列表。
中括号方式构造列表有一个很重要的特性:列表解析,不少地方也称为"列表推到"。例如:
>>> [x for x in 'abcdef'] ['a', 'b', 'c', 'd', 'e', 'f']
list()是直接将所给定的数据一次性所有构造出来,直接在内存中存放整个列表对象。列表推导方式构造列表比list()要快,且性能差距还挺大的。
列表支持+ *
符号操做:
>>> L = [1,2,3,4] >>> L1 = ['a','b','c'] >>> L + L1 [1, 2, 3, 4, 'a', 'b', 'c'] >>> [1,2] + list("34") [1, 2, '3', '4'] >>> L * 2 [1, 2, 3, 4, 1, 2, 3, 4] >>> 2 * L [1, 2, 3, 4, 1, 2, 3, 4]
能够经过+=
的方式进行二元赋值:
>>> L1 = [1,2,3,4] >>> L2= [5,6,7,8] >>> L1 += L2 >>> L1 [1, 2, 3, 4, 5, 6, 7, 8]
L1 += L2
的赋值方式对于可变序列来讲(好比这里的列表),性能要好于L1 = L1 + L2
的方式。前者直接在L1的原始地址内进行修改,后者新建立一个列表对象并拷贝原始L1列表。但实际上,性能的差距是微乎其微的,前面说过列表中保存的是元素的引用,因此拷贝也仅仅只是拷贝一些引用,而非实际数据对象。
列表是序列,序列类型的每一个元素都是按索引位置进行存放的,因此能够经过索引的方式取得列表元素:
>>> L = [1,2,3,4,5] >>> L[0] 1 >>> L = [ ... [1,2,3,4], ... [11,22,33,44], ... [111,222,333,444] ... ] >>> L[0][2] 3 >>> L[1][2] 33 >>> L[2][2] 333
固然,也能够按索引的方式给给定元素赋值,从而修改列表:
>>> L = [1,2,3,4,5] >>> L[0] = 11
经过赋值方式修改列表元素时,不只能够单元素赋值修改,还能够多元素切片赋值。
>>> L[1:3] = [22,33,44,55] >>> L [11, 22, 33, 44, 55, 4, 5]
上面对列表的切片进行赋值时,其实是先取得这些元素,删除它们,并插入新数据的过程。因此上面是先删除[1:3]
的元素,再在这个位置处插入新的列表数据。
因此,若是将某个切片赋值为空列表,则表示直接删除这个元素或这段范围的元素。
>>> L [11, 22, 33, 44] >>> L[1:3] = [] >>> L [11, 44]
但若是是将空列表赋值给单个索引元素,这不是表示删除元素,而是表示将空列表做为元素嵌套在列表中。
>>> L = [1,2,3,4] >>> L[0] = [] >>> L [[], 2, 3, 4]
这两种列表赋值的区别,在理解了前文所说的列表结构以后应该不难理顺。
列表是一种序列,因此关于序列的操做,列表均可以用,好比索引、切片、各类序列可用的函数(好比append()、extend()、remove()、del、copy()、pop()、reverse())等。详细内容参见:python序列操做
除了这些序列通用操做,列表还有一个专门的列表方法sort,用于给列表排序。
sort()是列表类型的方法,只适用于列表;sorted()是内置函数,支持各类容器类型。它们均可以排序,且用法相似,但sort()是在原地排序的,不会返回排序后的列表,而sorted()是返回新的排序列表。
>>> help(list.sort) Help on method_descriptor: sort(...) L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE* >>> help(sorted) Help on built-in function sorted in module builtins: sorted(iterable, /, *, key=None, reverse=False) Return a new list containing all items from the iterable in ascending order. A custom key function can be supplied to customize the sort order, and the reverse flag can be set to request the result in descending order.
本文仅简单介绍排序用法。
例如列表L:
>>> L = ['python', 'shell', 'Perl', 'Go', 'PHP']
使用sort()和sorted()排序L,注意sort()是对L直接原地排序的,不是经过返回值来体现排序结果的,因此无需赋值给变量。而sorted()则是返回排序后的新结果,须要赋值给变量才能保存排序结果。
>>> sorted(L) ['Go', 'PHP', 'Perl', 'python', 'shell'] >>> L ['python', 'shell', 'Perl', 'Go', 'PHP'] >>> L.sort() >>> L ['Go', 'PHP', 'Perl', 'python', 'shell']
不难发现,sort()和sorted()默认都是升序排序的(A<B<...<Z<a<b<...<z
)。它们均可以指定参数reverse=True
来表示顺序反转,也就是默认获得降序:
>>> L.sort(reverse=True) >>> L ['shell', 'python', 'Perl', 'PHP', 'Go']
在python 3.x中,sort()和sorted()不容许对包含不一样数据类型的列表进行排序。也就是说,若是列表中既有数值,又有字符串,则排序操做报错。
sort()和sorted()的另外一个参数是key
,它默认为key=None
,该参数用来指定自定义的排序函数,从而实现本身须要的排序规则。
例如,上面的列表再也不按照默认的字符顺序排序,而是想要按照字符串的长度进行排序。因此,自定义这个排序函数:
>>> def sortByLen(s): ... return len(s)
而后经过指定key = sortByLen
的参数方式调用sort()或sorted(),在此期间还能够指定reverse = True
:
>>> L = ['shell', 'python', 'Perl', 'PHP', 'Go'] >>> sorted(L,key=sortByLen) ['Go', 'PHP', 'Perl', 'shell', 'python'] >>> L.sort(key=sortByLen,reverse=True) >>> L ['python', 'shell', 'Perl', 'PHP', 'Go']
再例如,按照列表每一个元素的第二个字符来排序。
def f(e): return e[1] L = ['shell', 'python', 'Perl', 'PHP', 'Go'] sorted(L, key=f) L.sort(key=f)
更多的排序方式,参见:sorting HOWTO。好比指定两个排序依据,一个按字符串长度升序排,长度相同的按第2个字符降序排。用法其实很简单,不过稍占篇幅,因此本文不解释了。
列表是一个序列,可使用in测试,使用for迭代。
例如:
>>> L = ["a","b","c","d"] >>> 'c' in L True >>> for i in L: ... print(i) ... a b c d
再说列表解析,它指的是对序列中(如这里的列表)的每一项元素应用一个表达式,并将表达式计算后的结果做为新的序列元素(如这里的列表)。
通俗一点的解释,以列表序列为例,首先取列表各元素,对每次取的元素都作一番操做,并将操做后获得的结果放进一个新的列表中。
由于解析操做是一个元素一个元素追加到新列表中的,因此也称为"列表推导",表示根据元素推导列表。
最简单的,将字符串序列中的各字符取出来放进列表中:
>>> [ i for i in "abcdef" ] ['a', 'b', 'c', 'd', 'e', 'f']
这里是列表解析,由于它外面使用的是中括号[]
,表示将操做后的元素放进新的列表中。能够将中括号替换成大括号,就变成了集合解析,甚至字典解析。但注意,没有直接的元组解析,由于元组的括号是特殊的,它会被认为是表达式的优先级包围括号,而不是元组构造符号。
取出元素对各元素作一番操做:
>>> [ i * 2 for i in "abcdef" ] ['aa', 'bb', 'cc', 'dd', 'ee', 'ff'] >>> L = [1,2,3,4] >>> [ i * 2 for i in L ] [2, 4, 6, 8] >>> [ (i * 2, i * 3) for i in L ] [(2, 3), (4, 6), (6, 9), (8, 12)]
解析操做和for息息相关,且都能改写成for循环。例如,下面两个语句获得的结果是一致的:
[ i * 2 for i in "abcdef" ] L = [] for i in "abcdef": L.append(i * 2)
可是解析操做的性能比for循环要更好,正符合越简单越高效的理念。
学过其余语言的人,估计已经想到了,解析过程当中对各元素的表达式操做相似于回调函数。其实在python中有一个专门的map()函数,它以第一个参数做为回调函数,并返回一个可迭代对象。也就是说,也能达到和解析同样的结果。例如:
>>> def f(x):return x * 2 ... >>> list(map(f,[1,2,3,4])) [2, 4, 6, 8]
map()函数在后面的文章会详细解释。