這樣寫好嗎?

閱讀時間約 8 分鐘
製作fractal圖案,由匈牙利生物學家Aristid Lindenmayer所開發的L-system是個好用的工具。在研究L-system時,在一個網站(https://understanding-recursion.readthedocs.io/en/latest/15%20L-System.html)中看到了一段程式碼,一段乍看之下覺得挺詭異,懷疑是不是寫錯,但搞清楚之後卻拍案叫絕,冷靜下來後卻覺得這樣寫不怎麼好的程式碼。在研究這段程式碼的過程中,也才發現以前在讀官網的文件時,有點自以為是的忽略掉了一些東西,更激起是不是該再來從頭讀一讀官網文件的念頭。
那段程式碼要做的事情其實很單純,就是要把一串字串中的某些字元,代換成另一些字元。一個簡單的例子是:把一個字串裡頭的a、b、c分別以x、y、z來取代,其他的字元則不變。所以如果原本的字串是a-b+c*d,取代過後就會變成x-y+z*d。根據那個網站的寫法,程式會長這樣:
rule = {'a': 'x', 'b': 'y', 'c': 'z'}
string = 'a-b+c*d'
ans = ''.join([rule.get(char) or char for char in string])
讓人覺得詭異的部分是
rule.get(char) or char
邏輯運算子「or」得到的結果不是True就是False,怎麼可能最後可以得到字串?可是程式實際執行的結果,還真的可以得到正確答案。這究竟是怎麼一回事?
在網路上看了幾篇相關討論的文章,總算搞清楚了,不過要解釋的話,就得話說從頭了。
在進行邏輯判斷時,會有true和false兩種可能的結果。一般會用T或1來表示true;F或0來表示false。而在說明and、or、not、xor等邏輯運算子時,通常都會提到真值表。以or來說,真值表長這樣子:
A  B    A or B
F  F    F
F  T    T
T  F    T
T  T    T
稍微觀察一下就會發現,對於or來說,只要A、B中有任何一個是T,那最後的結果就是T。所以當A是T的時候,就已經可以確定結果是T了,後面的B就不用管它了。Python的官網文件中(Library Reference/Built-in Types/Boolean Operations),特別註明and、or是short-circuit operator,指的就是這種只要做到可以確定結果了,後面的部分就不做了的做法。就好像三戰兩勝制的比賽,比完前兩場,已經有一方贏了兩場,那就不用再比第三場了,因為勝負已定。這可是完全違反孔老夫子「行不由徑」的訓示。不過話又說回來,孔老夫子不會寫程式,不然應該也會同意這樣的做法。
因為and、or是short-circuit operator,所以它們的運算結果就不需要像真值表那樣,鉅細靡遺地列出所有狀況,而可以加以簡化。以or 來說,A or B的結果,可以寫成這樣的一條運算規則
if A is false, then B, else A
以前讀文件看到這條規則的時候並沒有太在意,覺得反正就是換湯不換藥,沒什麼特別的。沒想到,貓膩就藏在其中,一切的一切,都可以在這裡找到答案。不過,要想找出貓膩在哪,還得先瞭解一些東西。
前面提到過,false、true也可以用0、1來表示。有些程式語言比較大器,把除了0之外的整數,都當作true。至於Python呢,就更大開大闔了,把看起來和0會物以類聚的東西,例如None,都當作false,而其他的一切一切,都當作是true。在文件(Library Reference/Built-in Types)中,還特別有個小節「True Value Testing」專門在談這件事,並列出會被當成false的內建物件。
搞清楚Python對false、true的態度之後,再回頭看看那條規則就會發現,A or B所得到的,可能是A或B,而不非得是一直以來認為的true或false而已。所以啊,那條規則其實不是簡化版的真值表,而是在short-circuit操作下,or的廣義化運算規則。
萬事俱備了,可以來看看,為什麼那段讓人覺得詭異的程式,居然可以得到正確的結果。
先來看看rule.get(char)會得到什麼。
要從dictionary中取出某個key對應的value,可以直接指定key。例如rule['a']會得到'x',但如果指定的key不存在,則會傳回KeyError。另一種寫法是使用get()方法。例如rule.get('a')一樣會得到'x',不過,如果key不存在,傳回來的會是None。
這樣就很清楚了。當char不在rule裡頭時,rule.get(char)會得到None,而None會被視為false。根據or的那條廣義化運算規則,當A是false時,A or B會得到B,也就是說rule.get(char) or char會得到char。反之,當char在rule裡頭時,rule.get(char)會得到對應的value,而對於所有不是false的東西,都是true。根據or的廣義化運算規則,當A是true時,A or B會得到A,也就是說 rule.get(char) or char會得到rule中對應於char的字元。
九彎十八拐,繞了好大一圈,總算搞清楚這看起來很有學問的寫法了。不過一開始相遇時的驚艷,卻在激情過後逐漸轉為懷疑:這樣寫好嗎?寫成
''.join([rule[char] if char in rule else char for char in string])
不是更直接了當清楚易懂嗎?難怪網路上有人說用or的這種寫法,不是Pythonic的寫法。
除了讓人覺得不夠清楚易懂外,用or的這種寫法,其實是有點危險的,有可能會造成很難察覺的問題。
有天晚上剛躺上床準備去找老周泡茶聊天時,突然想到,如果rule裡頭某個key的value,是個會被當成是false的物件時,會發生什麼事?還能得到正確結果嗎?和老周泡茶時聊到這話題,他老人家一副莫測高深不置可否的樣子,只說:「夢裡尋他千百度,驀然回首……」,居然打起啞謎來了。其實啊,想也知道他不知道答案,畢竟他的專長領域是睡眠,不是程式。不過,與其在夢裡想他千百遍,不如實際電腦跑一遍。不動手,再大的夢想,都是空想。
實際測試的結果:真的會出問題!如果把rule裡頭'a'這個key的value改成整數0或空字串'',那'a'會被保留,不會被置換。使用or的寫法,雖然讓人覺得挺炫的,但還是少用為妙。
在葉李華的科科網(http://yehleehwa.net/index.htm)中,有篇「樞紐與轉捩點──小兵立大功的銀河帝國系列」(http://yehleehwa.net/empire.htm),提到關於科幻大師艾西莫夫的一則小故事:
一九五○年初,剛過完三十歲生日,他終於出版了生平第一本書──長篇科幻小說《蒼穹一粟》。這件事帶給他極大的鼓勵,為其職業作家生涯埋下重要的伏筆。
根據艾西莫夫自己的說法,這本書出版後,他正式將自己視為作家。因此,在撰寫下一部長篇小說的時候,他刻意捨棄之前的筆法,嘗試將一字一句寫得足夠有文學味。好在剛寫完兩篇樣章,一位編輯(後來成為他的好友)及時給了他當頭棒喝。
那位編輯說:「你可知道,『第二天早上太陽出來了』這句話,海明威會怎麼寫?」
艾西莫夫承認只聽說過海明威,但從未讀過他的小說。於是那位編輯宣佈答案:「第二天早上太陽出來了。」
這段僅僅十秒鐘的對話,給了艾西莫夫絕大的啟示。其後整整四十年,他始終堅守這個原則,盡量將文句寫得通俗易懂,從不刻意賣弄辭藻或文采(搞笑時例外)。不知不覺間,這種風格便成了他的金字招牌。
「第二天早上太陽出來了」,這寫法還真是有The Zen of Python的味道。原來,寫作跟寫程式,骨子裡還真是挺像的啊!
為什麼會看到廣告
avatar-img
15會員
129內容數
寫點東西自娛娛人
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
ysf的沙龍 的其他內容
寫程式最怕碰到的,就是信心滿滿地寫好程式後,發現結果不如預期,而且完全看不出問題出在哪裡。這種慘況可以分成兩種:一種是程式很長、很複雜,想要把心機很重,躲在幽暗深處的臭蟲給抓出來,即使有功能強大的除錯工具,都不是件簡單的事;另一種是程式沒幾行,一切看起來都很清楚正常,臭蟲根本沒地方躲藏,可是結果就是
解決了Spyder和turtle之間的不合後,就來畫些漂亮迷人的fractal圖案,也順便練習一下recursive function的寫法。
龜兔賽跑,第一回合兔子因為太輕敵,在半路上呼呼大睡睡過頭,輸了比賽。 雖然輸了第一回合的比賽,不過兔子並沒有灰心喪志,牠記取教訓,買了個功能齊全的運動手錶來戴,睡覺前先定好鬧鐘時間,這樣就不怕睡過頭而輸了比賽。從此龜兔賽跑,兔子照樣在半路上睡覺補充體力,但再也沒有因為睡過頭而輸了比賽。
「學程式,數學要很好嗎?」這問題的答案其實很簡單,就是:Yes and no。
「天啊!這程式怎麼這麼醜!」瞪著螢幕上先前寫的程式,不禁從心底冒出這樣的一句話。
或許就如官網文件中所說的,lambda function就只是syntactic sugar而已,所以也就沒特別在意,直到在設計Game of Life的輸入介面時,因為需要用到,兜兜轉轉,費了好些功夫和時間,總算對它的用途和用法有比較完整的認識。
寫程式最怕碰到的,就是信心滿滿地寫好程式後,發現結果不如預期,而且完全看不出問題出在哪裡。這種慘況可以分成兩種:一種是程式很長、很複雜,想要把心機很重,躲在幽暗深處的臭蟲給抓出來,即使有功能強大的除錯工具,都不是件簡單的事;另一種是程式沒幾行,一切看起來都很清楚正常,臭蟲根本沒地方躲藏,可是結果就是
解決了Spyder和turtle之間的不合後,就來畫些漂亮迷人的fractal圖案,也順便練習一下recursive function的寫法。
龜兔賽跑,第一回合兔子因為太輕敵,在半路上呼呼大睡睡過頭,輸了比賽。 雖然輸了第一回合的比賽,不過兔子並沒有灰心喪志,牠記取教訓,買了個功能齊全的運動手錶來戴,睡覺前先定好鬧鐘時間,這樣就不怕睡過頭而輸了比賽。從此龜兔賽跑,兔子照樣在半路上睡覺補充體力,但再也沒有因為睡過頭而輸了比賽。
「學程式,數學要很好嗎?」這問題的答案其實很簡單,就是:Yes and no。
「天啊!這程式怎麼這麼醜!」瞪著螢幕上先前寫的程式,不禁從心底冒出這樣的一句話。
或許就如官網文件中所說的,lambda function就只是syntactic sugar而已,所以也就沒特別在意,直到在設計Game of Life的輸入介面時,因為需要用到,兜兜轉轉,費了好些功夫和時間,總算對它的用途和用法有比較完整的認識。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
有次,辦公室的同事跟我說,某天他就讀國小的兒子去學校時,發現座位上放著情書,而且還有兩封!不僅如此,這兩封情書居然是來自班上一對很要好的朋友!(以下稱作A女及B女)。據說,B女的那封信還是A女幫忙放的!?(等等,劇情這樣發展不太合理吧…)。 接著,同事的兒子說,A女的信裡面寫著「XXX
Thumbnail
你想寫文案? 分享自己的產品卻不知道怎麼寫??有好的產品卻賣不出去?而要撰寫一篇能夠轉換率突破100%的廣告文案,似乎是一個夢想,但這並不是遙不可及的。只要掌握了正確的技巧和方法,你也可以輕鬆地創作出讓人難以抗拒的文案。
Thumbnail
以下是我對《東京復仇者》的改編 **故事開頭** 故事的開頭與原作相同,26歲的武道在車站月台上被一群不良少年推下月台,穿越時空回到12歲。他決心利用這個機會,拯救摯友日向和東京卍會。 **武道努力變強** 武道回到12歲後,加入了東京卍會,並開始努力變強。他向東京卍會的成員學習
學測作文占學測國文總成績之50%,進而依此計算級分與五標,因此作文整整占了一半的比重,是108課綱新式學測中十分重要的改變。加上分科測驗不再考國文,學測國文直接定生死,準備作文就成了其中至關重要的一環。 但畢竟是考試作文,有評分規則與給分標準這個「拿高分的線索」,它們可以說是閱卷老師的審美和喜好,
Thumbnail
編劇書中討論了影集、電影的情節設計,以情節為主的觀點。 本文則偷渡了作者的一些觀影心得,以及對編劇技巧應用於寫作上的思考。 本文可能適合文字寫作者參考,對編劇則比較沒用。
Thumbnail
閱讀日記「故事行銷」⋯原來該這樣寫! 這是台灣作家「李洛克」寫的書,同樣他也是名小說家跟編劇,所謂的故事行銷大家會想到什麼呢?應該是很多企業故事吧!但這些企業故事能否打動人心呢?他們的用詞精準嗎?能讓讀者感同深受嗎?很多都用自己懂的語言,譬如:週轉困難⋯沒了!誰知道「週轉困難」有多困難!他在本書中
Thumbnail
每個人都擁有不同的生活觀,價值觀,以及對事物的看法。當你毫不猶豫地分享自己的觀點時,你會不知不覺地吸引到一群志同道合的人,他們將成為你的忠實粉絲。 本文將告訴你如何在社群媒體中,通過表達自己的獨特觀點,吸引更多這樣的人,讓他們成為你生活的重要一部分。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
有次,辦公室的同事跟我說,某天他就讀國小的兒子去學校時,發現座位上放著情書,而且還有兩封!不僅如此,這兩封情書居然是來自班上一對很要好的朋友!(以下稱作A女及B女)。據說,B女的那封信還是A女幫忙放的!?(等等,劇情這樣發展不太合理吧…)。 接著,同事的兒子說,A女的信裡面寫著「XXX
Thumbnail
你想寫文案? 分享自己的產品卻不知道怎麼寫??有好的產品卻賣不出去?而要撰寫一篇能夠轉換率突破100%的廣告文案,似乎是一個夢想,但這並不是遙不可及的。只要掌握了正確的技巧和方法,你也可以輕鬆地創作出讓人難以抗拒的文案。
Thumbnail
以下是我對《東京復仇者》的改編 **故事開頭** 故事的開頭與原作相同,26歲的武道在車站月台上被一群不良少年推下月台,穿越時空回到12歲。他決心利用這個機會,拯救摯友日向和東京卍會。 **武道努力變強** 武道回到12歲後,加入了東京卍會,並開始努力變強。他向東京卍會的成員學習
學測作文占學測國文總成績之50%,進而依此計算級分與五標,因此作文整整占了一半的比重,是108課綱新式學測中十分重要的改變。加上分科測驗不再考國文,學測國文直接定生死,準備作文就成了其中至關重要的一環。 但畢竟是考試作文,有評分規則與給分標準這個「拿高分的線索」,它們可以說是閱卷老師的審美和喜好,
Thumbnail
編劇書中討論了影集、電影的情節設計,以情節為主的觀點。 本文則偷渡了作者的一些觀影心得,以及對編劇技巧應用於寫作上的思考。 本文可能適合文字寫作者參考,對編劇則比較沒用。
Thumbnail
閱讀日記「故事行銷」⋯原來該這樣寫! 這是台灣作家「李洛克」寫的書,同樣他也是名小說家跟編劇,所謂的故事行銷大家會想到什麼呢?應該是很多企業故事吧!但這些企業故事能否打動人心呢?他們的用詞精準嗎?能讓讀者感同深受嗎?很多都用自己懂的語言,譬如:週轉困難⋯沒了!誰知道「週轉困難」有多困難!他在本書中
Thumbnail
每個人都擁有不同的生活觀,價值觀,以及對事物的看法。當你毫不猶豫地分享自己的觀點時,你會不知不覺地吸引到一群志同道合的人,他們將成為你的忠實粉絲。 本文將告訴你如何在社群媒體中,通過表達自己的獨特觀點,吸引更多這樣的人,讓他們成為你生活的重要一部分。