iT邦幫忙

3

[不做怎麼知道系列之Android開發者的30天後端養成故事 Day3] - 讓熱情燒一會兒 #別間斷很重要 #Python資料結構

https://ithelp.ithome.com.tw/upload/images/20200205/201245489hVQmv4AWB.png

基礎語法後,沒意外就是進階了吧 !?

嘖嘖嘖,別急,還記得 Day1 參考了 backend roadmap 後所提出的七步驟嗎?,今天我們要正式踏入第一步驟 - 資料結構,我已經聽到你們的「蛤~~~到第三天了還在第一步驟 !?」,俗話說得好:「走得慢一點,踩得穩一點,重要的是走得遠。」,人生不是短跑衝刺競賽,或許你們和 RS 一樣是社會新鮮人,或許有些社會歷練,又或許你們已是社會老鳥,但至少你我都至少還期望自己會再戰個幾年吧 ?,就是這個 幾年,有個幾年的時間就夠了,我們只是前面走得慢一點,瞭解得深一點,後來會省很多 Debug 的時間,到時候才知道誰走的快。

沒有頁碼的目錄

避免加上程式碼會讓文章冗長,所以先上目錄,各位看官可以挑選自己有興趣或不足的章節:

Python 的 資料結構

  • list

    在 Python 的 listJavaKotlinArrayList 概念幾乎一樣,你可以把它們想成同一個結構,都是 有序可變,可是要注意的是 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 的 appendpop 操作即可。

        # 因 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 的話,你可以利用上面提到的 appendpop 來當作 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:資料結構,裡面提到很多以上資料結構的操作細節。

https://images.pexels.com/photos/2202685/pexels-photo-2202685.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260

攝影師:Vladislav Vasnetsov,連結:Pexels

單日心得總結

其實 RS 在寫文章的時候,都很糾結到底要舉多少範例,每個結構的各種用法就已經足夠寫成一篇文章,希望各位看官們不要太鞭我的範例包含太少 QQ。

今天超開心能參加 好想工作室 的羽球團,趁這個機會認識到好多大神們,不然平常都是待在自己位置上敲鍵盤沒機會聊天,開勳 <3。

這連續兩天都在學習觀念和語法,真的有點太無趣,明天就一起進入到 Django 的世界吧!

我是 RS,這是我的 不做怎麼知道系列 文章,我們 明天見。



尚未有邦友留言

立即登入留言