# Python 推導式(Comprehension)與賦值表達式(Walrus Operator) 如有錯誤歡迎糾正,小弟正在學習中 ## 推導式(comprehension) 推導式是python獨有的方法可簡潔for loop,來看例子 正常情況for loop ### list ``` python greater_than_five = [] numbers = [1,2,3,4,5,6,7,8,9,10] for number in numbers: if number > 5: greater_than_five.append(number) ``` 從程式中簡單的邏輯卻不太簡潔,我們可以漂亮的改用推導式 ``` python numbers = [1,2,3,4,5,6,7,8,9,10] greater_than_five= [n for n in numbers if n > 5] print(greater_than_five) >> [6, 7, 8, 9, 10] ``` 推導式好處在將結果賦予變數,不須再for loop外層宣告變數,也不用再用append加入list,簡潔了程式 ### dict ``` python numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] greater_than_five = {f'loop_{n}': n for n in numbers if n > 5} print(greater_than_five) >>> {'loop_6': 6, 'loop_7': 7, 'loop_8': 8, 'loop_9': 9, 'loop_10': 10} ``` ### 推導式須注意部分 推導式好用,但有些部分要注意 - 過多迴圈避免使用推導式 如果for loop超過三個就不建議用推導式了,在閱讀上與維護會相當複雜 三個for loop用推導式簡直是地獄 ``` python # 使用推導式生成三維列表,並在每層嵌套中進行條件判斷 result = [[[i * j * k for k in range(3) if i * j * k % 2 == 0] for j in range(3)] for i in range(3)] ``` 正常foor loop,較上面例子看起來好閱讀一些 ``` result = [] for i in range(3): layer = [] for j in range(3): row = [] for k in range(3): value = i * j * k if value % 2 == 0: row.append(value) layer.append(row) result.append(layer) ``` > 💡補充知識:在程式上請避免縮排大於三,迴圈也盡量避免超過二,避免增加閱讀上困難,如果沒辦法避免也請用[Early Retrurn Pattern](https://hackmd.io/4H1J5p1GTOG3f90I7u-bRA)來處理 - 需評估判斷式是否會增新增條件 當判斷條件為複數或以上就不推薦使用推導式,尤其是預期未來業務邏輯會增加,那就會讓閱讀上與程式更加混亂與擴充邏輯 判斷式條件複數時難以閱讀,個人習慣是條件大於三不使用推導式,如果複數條件會看條件複雜性來決定是否使用推導式,以下例子對於python不熟悉的人閱讀會比較吃力,但以條件來看複雜性不算高還能接受 ``` python data = [ {"name": "Alice", "age": 25, "city": "New York"}, {"name": "Bob", "age": 30, "city": "San Francisco"}, {"name": "Charlie", "age": 35, "city": "New York"}, {"name": "David", "age": 40, "city": "Chicago"} ] # 複雜條件:選擇年齡大於 30 且城市為 New York 的人 filtered = [person for person in data if person["age"] > 30 and person["city"] == "New York"] ``` 相較於單純用for loop還比較清晰 ``` python filtered = [] for person in data: if person["age"] > 30 and person["city"] == "New York": filtered.append(person) ``` - 縮排需要注意,避免增加閱讀上的困難 例子:篩選合格的學生成績 假設我們有一組學生的考試成績數據,想要篩選出所有及格的成績(及格分數為 60 分及以上),並將這些成績加入到一個新列表中。 沒推導式的寫法 ``` python grades = [ [55, 78, 62], [88, 45, 91], [76, 58, 73] ] passing_grades = [] for student_grades in grades: # 外層迴圈,遍歷每一個學生的成績 for grade in student_grades: # 內層迴圈,遍歷該學生的每一科成績 if grade >= 60: # 如果成績及格 passing_grades.append(grade) # 將及格成績加入新列表 ``` 改成推導式但沒排版,非常難以閱讀 ``` python grades = [ [55, 78, 62], [88, 45, 91], [76, 58, 73] ] passing_grades = [grade for student_grades in grades for grade in student_grades if grade >= 60] print(passing_grades) ``` 來看有排版部分,這是我個人習慣,一行只會有一個for loop或if,與上面對比清晰好閱讀 ``` python grades = [ [55, 78, 62], [88, 45, 91], [76, 58, 73] ] passing_grades = [grade for student_grades in grades for grade in student_grades if grade >= 60] print(passing_grades) ``` > 💡迴圈寫法是由上而下,而推導式相反會由下至上,這邊可能要注意 ### 推導式好處 - 程式簡潔 - 需要for loop量大的數據會增加效能,因為for loop call append()降低效能 ## 賦值表達式 Python 3.8 才有的功能,也被稱為海象運算符(Walrus Operator),符號為 :=(很像象牙)。它允許在表達式中進行賦值操作,來實際舉例會比較易懂 例子: 需要檢查使用者輸入的長度是否大於5,如果小於5也請告知使用者長度還少多少 沒有用賦值表達是寫法 ``` python user_input = input("Enter a string: ") length = len(user_input) if length > 5: print(f"Input is long enough: {user_input}") else: print(f"Input is too short. Needs {5 - length} more characters.") ``` 使用賦值表達式可以省去變數宣告,也簡潔了程式碼 ``` python if (user_input := input("Enter a string: ")): length = len(user_input) if length > 5: print(f"Input is long enough: {user_input}") else: print(f"Input is too short. Needs {5 - length} more characters.") ``` ### 賦值表達式需注意部分 - 當要使用賦值表達式在運算結果需要特別注意()範圍,否則結果會不如你預期 例子1: 需要儲存5-3結果大於1然後再乘10 括號範圍: (result:=(5-3)) ``` python if (result:=(5-3)) >1: cal = result*10 print(cal) >>> 20 ``` 例子2:將外圍括號去除,會發現結果不如預期, 括號範圍:無 結果: result 值會被賦值為 (5-3) > 1 result 會是 bool True,True*10 結果就會是10 ``` python if result:=(5-3) >1: cal = result*10 print(cal) >>> 10 ``` 例子3 括號範圍:(result:=(5-3) >1) 結果: 括號條件result也是bool True,所以最終 cal為 10 ``` python if (result:=(5-3) >1): cal = result*10 print(cal) ``` ### 賦值表達式優缺點 優點 - 簡潔省去多餘的變數宣告 缺點 - 不熟悉python 3.8的開發者可能看不懂 [1] stackoverflow - Why is a list comprehension so much faster than appending to a list?https://stackoverflow.com/questions/30245397/why-is-a-list-comprehension-so-much-faster-than-appending-to-a-list