一文了解Python數據結構

本文將詳細介紹 Python 的六大數據結構,包括數值、字符串、列表、元組、集合、字典等。閱讀本文預計需要 15 min。

1. 前言

數據結構對編程中非常重要的一部分,掌握 Python 數據結構非常必要。本文主要總結 Python 六大數據結構:

  • 數值
  • 字符串
  • 列表
  • 元組
  • 集合
  • 字典

2. 數值

Python 中有 3 種數值類型,分別是整型(int)、浮點型(float)、複數型(complex)。此外布爾型(bool)是整型的子類。通過下面的例子來直觀感受一下:

# 多個變量賦值
a, b, c, d = 10, 6.66, 10+5j, False
print(f"a的類型爲:{type(a)}")  # type(x) 可以查看 x 的類型
print(f"b的類型爲:{type(b)}")
print(f"c的類型爲:{type(c)}")
print(f"d的類型爲:{type(d)}")

輸出結果:
a的類型爲:<class 'int'>
b的類型爲:<class 'float'>
c的類型爲:<class 'complex'>
d的類型爲:<class 'bool'>

3. 字符串

文本信息是一種非常重要的信息。在 Python 中,字符串來充當這種角色。在 Python 中字符串是不可變對象,不可以被修改,要修改只能通過重新開闢內存空間,創建新的對象來實現。

這裏需要說明一下,Python 中變量更像一個標籤,這個標籤指向存儲了數據的地址,我們可以通過 id() 函數來查看對象的內存地址。

s = 'a'
print(f's 變量的值是:{s},s 變量的地址是:{id(s)}')
s += 'b'  # 等價於 s = s + 'b'
print(f's 變量的值是:{s},s 變量的地址是:{id(s)}')

結果輸出:
s 變量的值是:a,s 變量的地址是:2014533253552
s 變量的值是:ab,s 變量的地址是:2014533384432

通過上面這個例子我們可以看到,字符串不可以被改變,一旦改變,內存地址就會發生變化。相當於重新賦值。

3.1 創建字符串

創建字符串有以下幾種方式:單引號、雙引號、三引號、str()函數。代碼直觀演示如下:

s1 = 'a'  # 單引號創建單行字符串
s2 = "b"  # 創建單行字符串
s3 = '''
這是三個單引號創建的
多行字符串!'''
s4 = """
這是三個雙引號創建的
多行字符串!"""
s5 = str([1, 2, 3])  # [1, 2, 3] 是列表,後面會講,這裏是把列表轉化爲字符串
print(f'單引號創建的單行字符串內容是:{s1}')
print(f'雙引號創建的單行字符串內容是:{s2}')
print(f'三個單引號創建的多行字符串內容是:{s3}')
print(f'三個雙引號創建的多行字符串內容是:{s4}')
print(f'str() 函數創建的字符串內容是:{s5}')

輸出結果:
單引號創建的單行字符串內容是:a
雙引號創建的單行字符串內容是:b
三個單引號創建的多行字符串內容是:
這是三個單引號創建的
多行字符串!
三個雙引號創建的多行字符串內容是:
這是三個雙引號創建的
多行字符串!
str() 函數創建的字符串內容是:[1, 2, 3]

3.2 下標和切片

下標在 Python 中是一個編號,字符串、列表、元組都可以用下標來索引,我們可以通過下標來找到其對應的元素。注意:下標是從 0 開始編號的,用0-(n-1)索引。假如我們有一個字符串 s = 'abcd',現在我想得到這個字符串的第 1 個元素,那麼我們可以通過 s[0] 得到第 1 個元素。此外 Python 還支持負數索引,用(-n)-(-1)來索引。s[-1]表示倒數第 1 個元素。測試如下:

In [1]: s = 'abcd'

In [2]: s[0]
Out[2]: 'a'

In [3]: s[-1]
Out[3]: 'd'

切片是指對操作的對象截取其中一部分的操作。字符串、列表、元組都支持切片操作。切片操作是一個淺拷貝操作,它只拷貝第一層對象。關於深拷貝和淺拷貝,留作以後探討。切片的語法規則是:[開始:結束:步長],注意以下幾點:

  1. 開始、結束、步長省略時,開始默認從頭開始,結束默認到結尾,步長默認爲 1。
  2. 結束取不到,如: s = '0123's[0:3] 截取的是s[0], s[1], s[2],截取不到 s[3],即取前不取後。
  3. 切片支持負數索引。

測試如下:

In [1]: s = '0123456789'

In [2]: s[0:3]
Out[2]: '012'

In [3]: s[-3:-1]
Out[3]: '78'

In [4]: s[0:10:2]
Out[4]: '02468'

3.3 字符串的常用操作

我們可以對字符串進行很多操作,比如首字母大寫、查找、替換、拼接等等。在 Python 中內置了很多字符串操作的方法,我們可以通過 dir(str) 查看字符串的內置方法,在通過 help(str.function)查看該方法的用法。或者直接打開下載的 Python 官方文檔檢索查看 str 對象的方法。
這裏主要列幾個用的比較多的方法。

str.split(sep=None, maxsplit=-1) 方法常用來把字符串轉化爲列表(list),它將字符串 strsep 爲分隔符,以 maxsplit 爲分割次數,轉化爲列表。測試如下:

In [18]: s = 'Python is a great language!'

In [19]: s.split(' ')
Out[19]: ['Python', 'is', 'a', 'great', 'language!']

In [20]: s.split(' ', 1)
Out[20]: ['Python', 'is a great language!']

In [21]: s.split()
Out[21]: ['Python', 'is', 'a', 'great', 'language!']

str.join(iterable) 方法常用來把列表(list)轉化爲字符串,是一種常用高效的字符串拼接方法,它的含義是用 str去拼接iterable中的每個元素。這裏需要注意:iterable 的每個元素必須都是字符串類型,否則會報 TypeError。測試如下:

my_list = ['Python', 'is', 'great!']
result = ' '.join(my_list)  # 用空格連接 my_list 中的各個元素
print(result)

輸出結果:
Python is great!

如果將 my_list 更改爲 my_list = ['Python', 'is', 'great!', 3],那麼程序會報錯,TypeError: sequence item 3: expected str instance, int found。因爲 3int 類型。

此外還可以通過 + 實現字符串拼接功能。在字符串中,我們可以用 +*來增加字符串。其中 + 是拼接字符串,* 是重複字符串。測試如下:

name_info = '我的名字是Jock,'
age_info = '年齡是25歲!'
my_info = name_info + age_info  # 這裏加號把兩個字符串拼接在一起
print(f'name_info + age_info 結果是:{my_info}')
s = 'abc'
s *= 3  # 等價於 s = s * 3,即把 'abc' 重複 3 次
print(s)

輸出結果:
name_info + age_info 結果是:我的名字是Jock,年齡是25歲!
abcabcabc

str.replace(old, new[, count]) 方法是實現將字符串 str 中所有的old 字符片段替換爲 new 片段,如果給出了 count 參數,則只替換 count 次。測試如下:

In [11]: s = 'abcdabcdabcd'

In [12]: s.replace('a', 'f', 1)
Out[12]: 'fbcdabcdabcd'

In [13]: s.replace('a', 'f')
Out[13]: 'fbcdfbcdfbcd'

str.strip([chars]) 方法常用來處理字符串的邊界,比如去除字符串兩端的空格等,它將字符串 str 兩側 [chars] 列表中出現的字符都去除,如果省略 [chars] 則默認去除字符串 str 兩側的空格。測試如下:

In [22]:  '   Python   '.strip()
Out[22]: 'Python'

In [23]: 'www.example.com'.strip('cmowz.')
Out[23]: 'example

4. 列表

列表(list)是 Python 中非常重要且常用的數據類型。在 Python 中 list 是一個可變序列。這裏的可變是指 list 的元素個數可以增加或減少。列表用 []包圍,每個元素用 , 分隔。

list 非常強大,我們可以把 list 當做一個大容器,什麼都可以往裏面裝,比如:字符串、字典、列表、元組等。此外列表也支持下標和切片操作,非常靈活強大。

4.1 創建列表

我們可以通過以下幾種方式創建一個列表。

  1. list_a = [],創建一個空列表,推薦使用。
  2. list_b = list(),使用 list() 函數創建一個空列表。
  3. list_c = [x for x in range(10)],使用列表推導式創建一個列表。

4.2 增加列表元素

往列表中增加元素主要有以下幾種方法:

  1. list.append(x):將元素 x 添加到 list 尾部,等價於 list[len(list):len(list)] = [x])
  2. list.extend(list_b):將 list_b 中所有的元素添加到 list 中,等價於 list += list_b
  3. list.insert(i, x):在 list 下標爲 i 的位置插入 x,等價於 list[i:i] = [x]
  4. +:列表也可以直接拼接 list_a += list_b

測試如下:

list_a = [1, 2]
list_a.append(3)
print(f'list_a = [1, 2],list_a.append(3) 是:{list_a}')
list_b, list_c = [1, 2, 3], [4, 5, 6]
list_b.extend(list_c)
print(f'list_b = [1, 2, 3],list_c = [4, 5, 6], list_b.extend(list_c) 是:{list_b}')
list_d = [1, 2, 3]
list_d.insert(0, 5)
print(f'list_d = [1, 2, 3],list_d.insert(0, 5) 是:{list_d}')
list_e, list_f = [1, 2, 3], [4, 5, 6]
print(f'list_e = [1, 2, 3],list_f = [4, 5, 6], list_e + list_f 是:{list_e + list_f}'')

結果如下:
list_a = [1, 2],list_a.append(3) 是:[1, 2, 3]
list_b = [1, 2, 3],list_c = [4, 5, 6], list_b.extend(list_c) 是:[1, 2, 3, 4, 5, 6]
list_d = [1, 2, 3],list_d.insert(0, 5)是:[5, 1, 2, 3]
list_e = [1, 2, 3],list_f = [4, 5, 6], list_e + list_f 是:[1, 2, 3, 4, 5, 6]

這裏提一下,append()、extend()、insert() 方法都是在原有的 list 上添加,不會開闢新的內存空間,而用 + 會開闢新的內存空間,增加開銷。應該根據具體需求靈活進行選擇。

4.3 刪除列表元素

刪除列表元素主要有以下方法:

  1. del list[index]:根據下標進行刪除,刪除 list 下標爲 index 的元素。
  2. pop list[index]:根據下標進行刪除,刪除並返回 list 下標爲 index 的元素。
  3. list.remove(x):根據值進行刪除,刪除 list 中 x 元素,一次只刪除一個 x。
  4. del list[:]:刪除 list 中的所有元素,list 變爲空列表。
  5. list.clear():刪除 list 中的所有元素,list 變爲空列表。
  6. del list: 刪除整個列表對象。

4.4 修改列表元素值

修改列表元素值的主要是通過下標來確定要修改的是哪個元素,然後才能修改。格式: list[index] = value 將 list[index] 的值修改爲 value。測試如下:

In [37]: list_a = [1, 2, 3]

In [38]: list_a[0] = 4

In [39]: list_a
Out[39]: [4, 2, 3]

4.5 查詢列表元素

查詢列表元素的值有以下幾種方法:

  1. list[index]:返回列表中下標是 index 的元素。
  2. in:判斷某個元素是否在列表中,如果在,返回 True,否則返回 False。
  3. not in:判斷某個元素是否在列表中,如果不在,返回 True,否則返回 False
  4. list.index(x):返回列表中元素 x 的下標。
  5. list.count(x);返回列表中元素 x 出現的次數。

4.6 列表的排序

列表可以通過下標索引,它是一個有序序列,所以我們可以對列表進行排序。排序的方法有以下兩種:

  1. list.sort(*, key=None, reverse=False):穩定的原地排序。默認將 list 由小到大排序,reverse=True 可改爲倒序,由大到小。
  2. sorted(list):對於原 list 沒有改變,返回一個排好序的列表,默認是升序,reverse=True 可改爲倒序,由大到小。
  3. list.reverse():將 list 翻轉。

4.7 列表作爲棧和隊列使用

在 Python 中所有可變數據結構都遵循一個設計原則:原地修改可變對象是沒有返回值的,或者說返回值是 None。比如 list 中的 sort、insert、remove 方法等。

列表可以作爲棧(stack)使用,可以快速的實現(LIFO)後進先出,通過 pop() 和 append() 方法即可。用法如下:

>>> stack = [3, 4, 5]
>>> stack.append(6)
>>> stack.append(7)
>>> stack
[3, 4, 5, 6, 7]
>>> stack.pop()
7
>>> stack
[3, 4, 5, 6]
>>> stack.pop()
6
>>> stack.pop()
5
>>> stack
[3, 4]

同時列表也可以做隊列(queue)使用,實現(FIFO)先進先出,通過 pop(0) 和 append() 方法實現。但是由於列表在末尾添加和刪除一個元素是非常快的,但是在開頭添加和刪除一個元素速度比較慢,因爲在列表的擡頭添加或刪除一個元素,都需要移動後面的所有元素。

這時候我們可以使用 collections.deque,它可以實現在開頭和結尾都快速的刪除和添加一個元素。用法如下:

>>> from collections import deque
>>> queue = deque(["Eric", "John", "Michael"])
>>> queue.append("Terry")           # Terry arrives
>>> queue.append("Graham")          # Graham arrives
>>> queue.popleft()                 # The first to arrive now leaves
'Eric'
>>> queue.popleft()                 # The second to arrive now leaves
'John'
>>> queue                           # Remaining queue in order of arrival
deque(['Michael', 'Terry', 'Graham'])

5. 元組

元組(tuple)是 Python 中一種不可變的序列。因爲元組是不變的序列,所以我們不可以對元組進行修改。元組用 ()包圍,每個元素用 , 分隔,只有一個元素時,也要有一個 ,

爲什麼有了列表,還要設計一個不可變的元組呢?因爲可變,雖然靈活,但是存在風險,所以元組不可變,代碼相對更加安全。

元組可以認爲是一種特殊的列表,除了會改變自身的方法不通用之外,其他的通用。比如列表中的 append()、extend()、insert()等方法不能用於元組。

創建一個元組我們有以下幾個方法:

  1. t = ():創建一個空元組,推薦。
  2. t = tuple():創建一個空元組。
  3. t = (1, ):創建只有一個元素的元組,注意這裏一定要有逗號。

元組其實也是可以”改變“的。元組中的元素是不可以改變的,但是如果元組中的元素是可變對象,比如 list 的話,那麼這時候這個可變對象是可以改變的。看下面的例子:

In [56]: t = (1, 2, 3)

In [57]: t[0] = 5
這裏會報錯:
TypeError: 'tuple' object does not support item assignment

In [58]: t = (1, [0, 1], 3)

In [59]: t[1][0] = 6

In [60]: t
Out[60]: (1, [6, 1], 3)

通過上面的例子我們可以發現,其實元組也是可以“改變”的,我們可以這樣理解,上面這個例子中,t = (1, [0, 1], 3),元組 t 中的第二個元素其實是指向了列表[0, 1]的地址,列表[0, 1] 的地址沒有改變,但是該地址的內存空間存儲的值可以改變。

6. 集合

Python 中集合(set)是一個無序、可哈希的集合。集合具有確定性、互異性、無序性。創建集合的意義:

  1. 利用集合來去重。假如我們要對 list_a 進行去重,那麼可以這麼操作。list_a = list(set(list_a)).
  2. 判斷一個數是否在集合。x in s 或者 x not in s。因爲集合是可哈希的,所以它的查找時間複雜度爲 O(1),效率遠高於列表。
  3. 此外我們還可以用集合來求交集、並集、補集等運算。

我們可以通過 s = set() 創建一個空集合,注意:s = {}創建的是一個空字典。

更多 set 的用法可以用查看官方文檔。

7. 字典

字典(dictionary)是 Python 中另一種極爲重要的數據類型,是 Python 中唯一一個映射容器,用途非常廣泛。字典也是可變的。字典是用{}包圍的,專門存儲 key: value,即鍵值對的容器,各鍵值對用逗號分隔。

它不同於列表和元組等序列通過下標來索引,字典是通過鍵(key)來索引的。

字典中鍵必須是不可變的:

  1. 通常我們用數字字符串 來作爲字典的鍵。
  2. 元組也可以作爲字典的鍵,前提是元組中不包含可變對象,比如 (1, 2, 3) 可以作爲鍵,但是 ([1, 2], 2) 不可以作爲字典的鍵。
  3. 列表不可以作爲字典的鍵。因爲列表是可變的。

7.1 創建字典

創建字典可以通過以下方式創建:

  1. d = {}:創建一個空字典。
  2. d = dict():利用 dict()函數創建一個空字典。

測試如下:

In [62]: a = dict(one=1, two=2, three=3)

In [63]: b = {'one': 1, 'two': 2, 'three': 3}

In [64]:  c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))

In [65]: d = dict([('two', 2), ('one', 1), ('three', 3)])

In [66]: e = dict({'three': 3, 'one': 1, 'two': 2})

In [67]: a == b == c == d == e
Out[67]: True

7.2 增加字典元素

往字典中添加元素,我們有以下幾種方法:

  1. d[key] = value :用這個操作來往字典中添加元素存在風險,可能會使得我有的 key-value 被更改,所以用這個方法前要用 key in d 進行鍵的判斷。
  2. d.update([other]):other 可以是另一個字典,也可以是其他可迭代的鍵值對。也存在覆蓋已有的 key-value 的風險。
  3. d.setdefault(key[, default]):當存在 key 時獲取它對應的值,如果不存在這個 key,就加入這個 key,並把它對應的值設爲 default ,並返回 default。default 默認是 None

7.3 刪除字典元素

刪除字典元素有以下幾種方法:

  1. del d[key]:刪除字典元素 d[key]。
  2. d.clear():清空字典,變爲空字典。
  3. del d:刪除字典。
  4. d.pop(key[, default]):如果 d 中存在 key 那麼刪除 key-value 鍵值對,並返回 key 對應的 value。如果 key 不存在,則返回 default,未指定 default 則報錯 KeyError 。
  5. d.popitem():刪除並返回一個鍵值對元組,即:(key, value)。注意:從 Python3.7 開始,刪除的鍵值對遵循後進先出原則(LIFO)。在版本 Python 3.7 之前是任意刪除返回一個鍵值對。

7.4 修改字典元素

我們可以通過 d[key] = value 來修改字典元素,如果 key 不存在,則會往字典中添加 key-value 鍵值對。

7.5 查詢字典元素

查詢字典中的元素我們有以下幾種方法:

  1. key in d:查詢 key 是否在 字典 d 中,如果在返回 True ,否則返回 False.
  2. key not in d:查詢 key 是否在 字典 d 中,如果不在返回 True ,否則返回 False.
  3. d[key]:返回 key 對應的 value。如果 key 不存在,報錯 KeyError
  4. d.get(key[, default]):這是 d[key] 的友好模式。如果 key 在字典中,返回其對應的 value,否則返回 default,default 默認爲 None。

7.6 字典的遍歷

  1. 遍歷字典的 key:for key in d
  2. 遍歷字典的 value: for value in d.values()
  3. 遍歷字典的項:for item in d.items()
  4. 遍歷字典的 key-value: for key, value in d.items()

示例如下:

d = {"one": 1, "two": 2, "three": 3, "four": 4}

print('遍歷字典的key')
for key in d:
    print(key)

print('遍歷字典的value')
for value in d.values():
    print(value)

print('遍歷字典的item')
for item in d.items():
    print(item)

print('遍歷字典的key-value')
for key, value in d.items():
    print(key, value)

結果輸出:
遍歷字典的key
one
two
three
four
遍歷字典的value
1
2
3
4
遍歷字典的item
('one', 1)
('two', 2)
('three', 3)
('four', 4)
遍歷字典的key-value
one 1
two 2
three 3
four 4

for 循環的用法,我們下次學習會總結。這部分中字符串、列表、字典非常重要,它們的方法也很多,很難全部記住。如果忘記了我們及時查看官方文檔的用法即可,不一定非要死記硬背。

8. 小結

學習這部分之後我們需要:

  1. 掌握可變對象和不可變對象區別。
  2. 掌握字符串、列表、元組、字典、集合的增刪改查操作。
  3. 瞭解下標和切片。
  4. 瞭解每一種數據結構的應用場景。

9. 巨人的肩膀

  1. The Python 3.8 Tutorial

推薦閱讀:

  1. 編程小白安裝Python開發環境及PyCharm的基本用法
  2. 一文了解Python基礎知識
  3. 一文了解Python數據結構
  4. 一文了解Python流程控制
  5. 一文了解Python函數
  6. 一文了解Python部分高級特性
  7. 一文了解Python的模塊和包
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章