python列表類型

列表類型簡介

列表類型是一個容器,它裏面能夠存聽任意數量、任意類型的數據。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

  • 列表中能夠存放、嵌套任意類型的數據
  • 列表中存放的是元素的引用,也就是各元素的地址,所以是列表可變對象
  • 列表是可變序列。因此各元素是有位置順序的,能夠經過索引取值,能夠經過切片取子列表

構造列表

有兩種經常使用的構造列表方式:

  1. 使用中括號[]
  2. 使用list()構造方法

使用(中)括號構建列表時,列表的元素能夠跨行書寫,這是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()是內置函數,支持各類容器類型。它們均可以排序,且用法相似,但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()函數在後面的文章會詳細解釋。

相關文章
相關標籤/搜索