嘖嘖嘖,別急,還記得 Day1 參考了 backend roadmap 後所提出的七步驟嗎?,今天我們要正式踏入第一步驟 - 資料結構,我已經聽到你們的「蛤~~~到第三天了還在第一步驟 !?」,俗話說得好:「走得慢一點,踩得穩一點,重要的是走得遠。」,人生不是短跑衝刺競賽,或許你們和 RS 一樣是社會新鮮人,或許有些社會歷練,又或許你們已是社會老鳥,但至少你我都至少還期望自己會再戰個幾年吧 ?,就是這個 幾年,有個幾年的時間就夠了,我們只是前面走得慢一點,瞭解得深一點,後來會省很多 Debug 的時間,到時候才知道誰走的快。
避免加上程式碼會讓文章冗長,所以先上目錄,各位看官可以挑選自己有興趣或不足的章節:
list
在 Python 的 list
和 Java、Kotlin 的 ArrayList
概念幾乎一樣,你可以把它們想成同一個結構,都是 有序、可變,可是要注意的是 list 裡面裝的資料,是不是可以容許 多種型別 在同一個 list ****?,在 Java 的世界,ArrayList 不能 裝不同型別,這句話會有爭議,因為聰明如你們的工程師們想出了各種解法,有興趣可以參考 Create an ArrayList with multiple object types?;在 Kotlin 的世界,和 Java 一樣也是 不能 裝不同型別,依舊有各種解法,可以參考 Declaring List of multiple types in Kotlin;而 Python 的 list 是 可以 裝下多種型別 的,所以在使用上必須特別注意,這也是 RS 為什麼在 Day2,花這麼多時間強調變數型別的原因。
以 RS 的使用經驗來說,RS 建議讓 list 只裝同樣型別的資料,在進行專案實作上,比較不會讓自己和其他人搞混,減少出錯的機會。而總是會有需要裝下不同型別資料的時候,就可以使用接下來介紹的 tuple
,晚點再說,先來看看怎麼用 list 吧。
# 先放入各種型別的變數
minteger = 10
mstring = "Hi, this is RS."
mfloat = 3.14159
incremental_list = range(10)
float_list = [8.787, -0.618, 3.14e+30]
# 用 中括號[] 包起來,
# 就是 python 宣告 list 的方法
# 再全部塞到一個混和型別的 list,
# 除了用變數放入,也可以直接塞入值
# list 內也可以塞入另一個 list
mix_type_list = [minteger, mstring,
mfloat, incremental_list, float_list,
"I bought a keychron k6, nice~"]
# ###############################
# 取用 list 內的資料的方式
# ###############################
# 可直接看到 list 全部的資料
print(mix_type_list)
# 輸出為: [10, 'Hi, this is RS.',
# 3.14159, range(0, 10),
# [8.787, -0.618, 3.14e+30],
# 'I bought a keychron k6, nice~']
# 可從前面數來的 index 取用
print(mix_type_list[1])
# 輸出為 Hi, this is RS.
# index 也可從後面數來
print(mix_type_list[-1])
# 輸出為 I bought a keychron k6, nice~
# 取用 list 內的 list 的資料,
# 可用 len(your_list) 來取得你的 list 長度
# list 不像陣列(Array)需要事先宣告大小
print(mix_type_list[len(mix_type_list)-2][0])
# 輸出為 8.787
as Stack
在 Python 想要使用 Stack 不需要自己實作,直接使用 list 的 append
和 pop
操作即可。
# 因 list 內建 append(), pop()
# 可以直接模擬出 stack 的效果
# Python 的 list 的最後一個逗號,
# 可以寫出來,也可以省略
list_as_stack = [0, 1, 2, 3, ]
print(list_as_stack)
# 輸出為 [0, 1, 2, 3]
# 在 list 的最後放入一個值
list_as_stack.append(4)
print(list_as_stack)
# 輸出為 [0, 1, 2, 3, 4]
# 從最後一項拿出
be_popped = list_as_stack.pop()
print(list_as_stack)
# 輸出為 [0, 1, 2, 3]
print(be_popped)
# 輸出為 4
# 值得注意的是,pop 可以傳入 index 參數,
# 這個 index 是從前面數過來的正順序,
# 而 pop() 的預設參數為 -1,
# 也就是指向最後一個,使用時需要自行注意!
# 如果要避免犯錯,可以自己用 list.pop()
# 實作出一個沒有參數的 pop() function,
# 強制只能 pop 最後一項
as Queue
在 Python 想使用 Queue 的話,你可以利用上面提到的 append
和 pop
來當作 queue,但是,官方文件有提到,這樣的使用效率不好,原因是因為 list 的查找實作方式適合取用最後一項,有興趣可以參考 Efficiency of using a Python list as a queue,想更瞭解的話,可以修演算法 (Algorithms) 的課程,通常都會教怎麼去判斷程式的執行效率。
官方建議,可以使用 deque
來解決效率問題,改用 popleft
,來取值。
# 依舊可以使用 list 的 append 和 pop
# 來達到 queue 的效果,但效率不佳
# 量大 且 時常需要新增、取出的時候
# 效率問題將會更明顯
list_as_queue = [0, 1, 2, 3]
print(list_as_queue)
# 輸出為 [0, 1, 2, 3]
# 與 stack 相同,是放到最後
list_as_queue.append(4)
print(list_as_queue)
# 輸出為 [0, 1, 2, 3, 4]
# 以 pop(0) 取出在 list 的第一項,
# 在實作面是從最後一項走訪到第一項
# 所以當你的 list size 越大,就越沒效率
out_of_queue = list_as_queue.pop(0)
print(list_as_queue)
# 輸出為 [1, 2, 3, 4]
print(out_of_queue)
# 輸出為 0
# 使用 collections.deque
# 將 list 轉為 deque,
# 再用 popleft(),取得第一項
from collections import deque
effective_queue = deque(list_as_queue)
print(effective_queue)
# 輸出為 deque([1, 2, 3, 4])
out_of_queue = effective_queue.popleft()
print(effective_queue)
# 輸出為 deque([2, 3, 4])
print(out_of_queue)
# 輸出為 1
tuple
這個就是在樓上 list 有提到的 tuple
,RS 建議適合用在 混和型別 的情況,通常是你有一堆資料要傳出去,要創一個 class 又太麻煩的時候,特別適合使用 tuple,tuple 還有一個特性是 不可變 (immutable),也就是說當你創立一個 tuple 後,如果要新增/刪減,那麼就需要重新再創一個,你不能修改它。
# tuple 可加小括號,也可不加,
# 但有加小括號的話,是比較好閱讀的
this_is_a_tuple = 10, 8.787, "哩賀"
tuple_with_parentheses =
("我是 RS", 1.7878, 99)
print(this_is_a_tuple)
print(tuple_with_parentheses)
# 還有一種情況是 RS 常用的,
# 就是在輸出一些很雜的資料的時候
import datetime
print("嗨 RS,", "現在時間是",
datetime.datetime.now(),
",\n本周天氣是", ["晴天", "陰天",
"晴天", "晴天", "晴天",
"晴天", "晴天"])
# 輸出為 嗨 RS,
# 現在時間是 2020-02-05 19:28:15.395380
# 本周天氣是 ['晴天', '陰天', '晴天',
# '晴天', '晴天', '晴天', '晴天']
dict (Dictionary)
如果有用過 Java 或 Kotlin 的捧油們,可以把 dict
想成 HashMap
,都是 <key, value> 配對的形式,使用方法非常彈性,key 和 value 可以放入各種型別,目前 RS 試過的 key 有不能放 list 、set 和 dict,都是 unhashable,大家可以玩玩看,非常有趣,可是實際的使用情境上,還是盡量不要這麼花式,不然連自己都不知道自己在寫什麼。關於 hashable 可以參考 What is the meaning of 'unhashable type' error in Python?
# dictionary 可以塞入的型別非常彈性
dictionary = {2048: "好玩", 3.14159: ("這是", "pi", "拉"),
"我是key": [1, 2, 3, 4, 5]}
print(dictionary)
# 輸出為 {2048: '好玩', 3.14159:
# ('這是', 'pi', '拉'),
# '我是key': [1, 2, 3, 4, 5]}
# 也可以額外新增一筆資料進去
dictionary[8.787] = {"裡面": "還可以包含另一個dict哦"}
print(dictionary)
# 輸出為 {2048: '好玩', 3.14159:
# ('這是', 'pi', '拉'), '我是key':
# [1, 2, 3, 4, 5], 8.787:
# {'裡面': '還可以包含另一個dict哦'}}
# 嘗試更多 key 能接受的型別
dictionary[("連key", "都可以是tuple")] = "太扯拉"
print(dictionary)
# 輸出為 {2048: '好玩', 3.14159:
# ('這是', 'pi', '拉'), '我是key':
# [1, 2, 3, 4, 5], 8.787:
# {'裡面': '還可以包含另一個dict哦'},
# ('連key', '都可以是tuple'): '太扯拉'}
set
和 dictionary 一樣,在 Java、Kotlin 中也有對應的結構 - HashMap
,而 set 的特性是 無排序、項目不重複,適合用在你有一些資料是不希望有重複值的時候,set 與 set 之間還有取交集(intersect
)、聯集(union
)、差集(difference
)。
# set 和 dictionary 都是用大括號包起來,
# 不要眼花看錯囉,這時候命名就很重要了。
this_is_set = {9527, "你跟我重複就只會剩一個哦",
"你跟我重複就只會剩一個哦", 9487, 2266, 9527}
print(this_is_set)
'''
輸出為
{'你跟我重複就只會剩一個哦', 2266, 9487, 9527}
'''
最後,推薦大家閱讀 (2018 12月) 輕鬆學習 Python:資料結構,裡面提到很多以上資料結構的操作細節。
攝影師:Vladislav Vasnetsov,連結:Pexels
其實 RS 在寫文章的時候,都很糾結到底要舉多少範例,每個結構的各種用法就已經足夠寫成一篇文章,希望各位看官們不要太鞭我的範例包含太少 QQ。
今天超開心能參加 好想工作室 的羽球團,趁這個機會認識到好多大神們,不然平常都是待在自己位置上敲鍵盤沒機會聊天,開勳 <3。
這連續兩天都在學習觀念和語法,真的有點太無趣,明天就一起進入到 Django 的世界吧!
我是 RS,這是我的 不做怎麼知道系列 文章,我們 明天見。
喜歡我的文章嗎? 趕快來看看我都發了什麼文章吧:我的文章目錄
歡迎閱讀我的上一篇: [不做怎麼知道系列之Android開發者的30天後端養成故事 Day2] - 建立自信心 #一起練Python語法 #不能拖 #先照著教學做
歡迎閱讀我的下一篇: [不做怎麼知道系列之Android開發者的30天後端養成故事 Day4] - 動手做做看 #捲起袖子 #初探Django # DjangoHelloWorld