AI 興起後,「學習新程式語言」這件事變得微妙。

以前我很願意為了寫好程式靜下心花點時間啃書把程式語言的基礎打好,因為依據經驗,練好基本功對開發效率及品質的投資報酬率很好。現在不一樣了,即使對語言一無所知,把需求餵給 Copilot、Cursor、ChatGPT、Claude (咦?全部都是 C 開頭),天上就會掉程式碼,而 AI 對 Python 格外精通,正確率特別高。換言之,當不下苦功也能寫出 Python,何苦認真從頭學?加上「學程式無用論」、「程序員即將失業」說法四起,內憂外患之際,每每想發奮,小惡魔便在耳邊「學這幹嘛?學這幹嘛?」、「用不到用不到用不到」... 過去寫過 Knockout、Angular 的新手筆記,從沒像 Python 如此艱難,哈。

前陣子收到龍哥的大作,紙本書加作者簽名,是創造學習儀式感的聖物啊,輟學危機暫時解除... 拖了快兩個月,Python 新手筆記 4 終於來了。

這篇整理 Dictionary、Tuple 跟 Set 的重點。(電子書連結: 為你自己學 PYTHON)

Dictionary (字典)

Dictionary 是處理歸納、統計邏輯很常用的資料結構,在 Python 當然不會缺席。Dictionary 在 Python 的表示方法跟 JavaScript 很像:{ 'name': 'Jeffrey', 'score': 32767, 'skills': ['C#', 'JavaScript', 'Python?'] }。以下用 Cheatsheet 的方式整理重點:

  • 用 dict() 建立:dict(name='Jeffrey', score=32767, skills=['C#', 'JavaScript', 'Python?'])
  • 用 List 建立:dict([['name', 'Jeffrey'], ['score', 32767]])
  • 用 Tuple 建立:dict((('name', 'Jeffrey'), ('score', 32767)))
  • 用鍵值清單建立:dict.fromkeys(['name', 'score']) 會建立值為 None 的 Dictionary {'name': None, 'score': None}
  • dict_name[key] 可取值,但鍵值不存在會 KeyError;若要允許鍵值不存在可改用 dict_name.get(key)dict_name.get(key, default_value)dict_name.setdefault(key, default_value) 嘗試取值,若不存在就設成指定值
  • Python 風格寫法 key in dict_name
  • Python 3.6+,Dictionary 會保留鍵值加入順序
    dict_name = { 'k1': 1, 'k3': 3, 'k4': 4, 'k2': 2 }
    keys = [*dict_name.keys()] # 補充:.values() 可取值,.items() 取
    print(keys, sep=", ") # ['k1', 'k3', 'k4', 'k2']
    # 簡化寫法
    print([*dict_name]) # ['k1', 'k3', 'k4', 'k2']
    
  • 計算個數 len(dict_name)、清空內容 dict_name.clear()、刪值 del dict_name[key]
  • 讀取並移除值 dict_name.pop(key)dict_name.pop(key, default_value) (取不到時給預設值)
    dict_name.popitem() 可取出 (key, value) Tuple
    while dict_name: # 有東西時為 True
        k, v = dcit_name.popitem()
        print(f"{k}: {v}")
    
  • 合併 merged = { **dict1, **dict2 }merged = dict1 | dict2 (Python 3.9+)、dict1 |= dict2 (用 dict2 內容新增或覆寫到 dict1)
  • 複製 copied = dict_name.copy()copied = { **dict_name }copied = dict(dict_name) 屬淺 Copy;深層複製:copied = dict_name.deepcopy()
  • 取得所有 Key / Value:dict_name.keys()dict_name.values(),跑迴圈取 Key/Value:
    for k, v in dict_names.items():
        print("{k}: {v}")
    
  • 注意:keys()、values()、items() 傳回的並不是 List,而是 dict_keys、dict_values、dict_items 型別,是一種 Generator (產生器),類似 C# 的 IEnumerable,避免一次將所有內容載入記憶體。以下實驗可窺一二:
    big_dict = { i: i for i in range(1000000) }
    keys1 = big_dict.keys()
    keys2 = list(big_dict.keys())
    # getsizeof(keys1) -> 40,getsizeof(keys1) -> 8000056
    
  • 字典也可以用推導式快速轉換資料,例如:
    nums = [1, 2, 3, 4]
    squars = { x: x**2 for i in nums }
    # zip 可將兩個 List 的元素一配一組成 Tuple
    fruit_price = { fruit: price for fruit, price in zip(['Apple','Banana'], [10, 20]) }
    
  • 字典的 key 必須是可雜湊的型別(如:數字、字串、位元組),否則會得到 unhashable type: 'list' 之類的訊息,List/Dictionary/Set 不行,Tuple 的話,看裡面元素的型別

Tuple

Python 的 Tuple 是不可變(Immutable)資料結構,宣告後不能更改,這也呼應前節最後一點,Tuple 能計算雜湊,可以當成 Dictionary 的 Key,但寫法跟用法很彈性,對來我說,有點太彈性。小記如下:

  • Tuple 符號是 ( ) (List 用 、Dictionary 用 ),中間要放什麼都成,例如:( 'Jeffrey', 32767, [ 1, 2, 3] ),如果要更懶一點,連 ( ) 都可以省了,寫成 t = 'Jeffrey', 32767, [ 1, 2, 3]
  • 若 Tuple 只有一個元素,要加上逗號 ( 'str', ),不然會被視為字串外加了括號
  • tuple(串列或字串) 可將元素展開,例如:tuple('Hello') = ('H', 'e', 'l', 'l', 'o')
  • Tuple 存取元素跟 List 有點像,可以用 t[0]、t[1]、t[-1],也可 t1 += more_elements 串接增加元素
  • len()/count()/index() 可用,但因 Tuple 不可變,不支援 insert()、remove()
  • 由於內容不可變,Tuple 的效能比 List 好一點 (1000 萬次,57ms vs 312ms,記憶體用量也略少),但一般會更著重它唯讀的特性
  • 複製 Tuple 的方法:tuple(orig_tuple)copy.copy(orig_tuple)orig_tuple[:] #切片,但由於 Tuple 不可變,實際上會指向同一份內容
  • 何時用 Tuple 而非 List? 1) 強調資料不可變 2) 混雜異質性資料(例如:有數字有字串有字典)

Set

Set 類似 C# 的 HashSet<T>,在 ChatGPT/Copilot 給的程式範例中常用來找不重複值。

  • Set 符號是用大括號 { 1, 2, 3, 4 }{ } 是空字典,沒有元素的 Set 可寫成 set()
  • 用 List、Tuple 轉成 Set 可得到不重複值,例如:set([ 1, 2, 3, 2, 3])
  • Set 的元素是沒有順序性,在不同機器上產生結果可能不同
  • 支援 .add() / .remove() 增刪元素,新增重複元素沒變化,但刪除不存在元素會產生 KeyError,可用 'to-find' in set_var 測試是否存在,或是改用 .discard() 找不到就算了,另有 clear() 可清空
  • Set 自帶 .copy() 方法,但不能切片
  • 交集: s1.intersection(s2) 或 s1 & s2
  • 聯集: s1.union(s2) 或 s1 | s2
  • 差集 s1.difference(s2) 或 s1 - s2 (找出 s1 有但 s2 沒有的元素)
  • 超集合:s1.issuperset(s2)
  • 子集合:s1.issubset(s2)、s1 ⇐ s2 (子集合或是相等)、s1 < s2 (嚴格子集合,只能是子集合,不可相等)
  • 若 Set 含 nan,由於 nan 不等於任何東西 (nan 也不等於 nan),無法用 .remove()/.discard() 移除。解法:{ item for item in s1 if item == item }
  • forzenset([ 9, 5, 2, 7]),不可 .add()/.remove()/.clear()

This post discusses this shift and provides a detailed Python tutorial on dictionaries, tuples, and sets, emphasizing their usage, key features, and practical examples.


Comments

# by Ming

前幾兩個月左右開始用python解決工作上的一些瑣事,包含系統管理用的腳本,當然也是vscode+copilot。解決幾件事情後,心裡想著:他媽的我堅持寫shell script那麼多年根本就是一個白癡!雖然這麼說的前提是因為有copilot輔助才能如魚得水啦!不過就算沒copilot,也早該用python

# by Jeffrey

to Ming, Shell Script 最大優點應是免安裝,但如果作業環境允許安裝 Python、下載 Package,是沒必要這麼刻苦。我自己的狀況是些環境不能安裝軟體或部署執行檔,沒武器可用時會寫 PowerScript 多點勝算。

Post a comment