by Sam Chiversby Sam Chivers

在〈《Python 功力提升的樂趣》筆記(一)Black、命名、壞味道〉中,我們提到了「data」這個不佳的變數名稱。

以及應該要用什麼樣的名稱取代它,與例外可以使用 data 的情況。

看過那段後,你可以發現,data 雖爛,但還是偶有派上用場的時候。雖然絕大部分的情況,我依舊會避免使用。

然而有一個變數名稱,我絕對不會用

比 data 更糟的變數名稱——result

當我遵守了好習慣,盡可能避免在程式碼中使用 data 命名後,本以為能從此過上幸福快樂的生活,但我錯了!

因為沒多久後我就發現,還有一個比 data 更駭人聽聞的變數名稱——result

和 data 相比,其糟糕的程度,簡直有過之而無不及。畢竟萬事萬物都有「result」,因果循環、生生不息,而且這個命名更加抽象,令人不禁想問:

到底是什麼結果?

result 命名的濫用,在「儲存呼叫函式的結果」時最為常見,難怪到處都是 result。


3 個代表性案例

不誇張地說,code review 時我看到 result 這個變數名稱,幾乎都會建議改掉。因為它太過籠統,讓人無法立刻了解這個變數的內容與用途。

甚至有一種噁心感。(內心 OS:就這麼懶得想名字?)

不過,若細看後發現,眼前的情況真的不容易命名,我可能會選擇睜一隻眼閉一隻眼,暫時就先算了吧!😷

但平心而論,這真的是少數。我遇到大部分使用 result 的情況,都是懶得想名字XD。無論如何,我自己寫程式時,不會考慮使用 result,而且我認為這並不難。

下面我們就舉 3 個代表性案例,來看看 result 到底有多糟糕。以及應該要用什麼名稱來取代它——基本上就是更直接、具體、精確的名稱。

一、從資料庫查詢訂單

1
2
3
4
5
6
7
# 不好的寫法
result = query_orders_from_database(customer_id)
...

# 更好的寫法
orders = query_orders_from_database(customer_id)
...

第一種典型的情況是,明明有更具體的名稱可以使用,卻偏偏用了籠統的 result。

這樣的寫法,讓人看了一頭霧水,不確定 result 到底是指什麼。

類似的例子還有求平均值、性別、數量等等,太多了,都有一個 result,但明顯都可以用更具體的名稱來取代。

事實上,如前所述,會把變數命名為 result,往往不是真的遇到什麼難以命名的情境,而是因為懶XD。可是這份懶惰,會讓你的程式碼變得難讀

其中的代價,不可謂不大。


二、檢查用戶是否有管理員權限

1
2
3
4
5
6
7
8
9
# 不好的寫法
result = check_user_is_admin(user_id)
if result:
...

# 更好的寫法
is_admin = check_user_is_admin(user_id)
if is_admin:
...

這是我認為最重要的一條守則,簡言之:你不應該使用 result 來表示「狀態」

尤其當這個狀態是一個布林值時,代表「操作成功與否」或「特定條件是否符合」等等情況,你更應該使用具體的名稱

這個時候,我們可以考慮使用充滿了「布林味」的變數名稱,比如has_permissionis_validis_success等等——而不是result

為什麼布林值最不適合用 result?

回傳內容如果由很多部分組成,此時確實不容易概括成一個名稱

要命名好這類的回傳結果,需要花一定時間思考、評估其合適性,並不輕鬆。所以有些開發者乾脆用 result 來表示,姑且算是一種 workaround 吧!情有可原。

但如果回傳只是一個布林值,那就沒有「內涵太複雜以至於不易命名」問題。因為布林就只有兩種可能性:True 或 False

此時再偷懶用 result,恐怕就說不太過去了。


三、使用 requests 發出 HTTP 請求

終於來你最常見到的情境了,使用requests(或httpx)發出 HTTP 請求,並將回傳的結果存入 result。

雖然大部分人都會將這個變數命名為 response,但還是有人會用 result——而且覺得兩者「其實也沒什麼不同」啊!

(這種「我覺得都差不多啊!」的思維才是真正嚇人的,你懂的。)

1
2
3
4
5
6
7
8
9
10
11
import requests

# 不好的寫法
result = requests.get("https://api.example.com/data")
if result.status_code == 200:
process_data(result.json())

# 更好的寫法
response = requests.get("https://api.example.com/data")
if response.status_code == 200:
process_data(response.json())

在這個例子中,使用 response 作為變數名稱會比使用 result 更加清晰和具描述性。

當其他開發者看到這段程式碼時,會立即明白這個變數存儲的是一個 HTTP response(通常就是requestsresponse物件),而不是某個抽象的「結果」。

如果隨意地命名為 result,後續使用該變數時,result 預期會有什麼屬性?什麼方法?一切都不明朗,因為它有無限可能

往往要回去看變數的定義部分,才能知曉 result 究竟代表什麼。

當這變數的生命週期愈長、呼叫的次數愈多,使用 result 名稱造成的「可讀性問題」就愈嚴重。

這個例子還有一個常見的「變形」——res

1
2
3
res = requests.get("https://api.example.com/data")
if res.status_code == 200:
process_data(res.json())

這麼巧!response 和 result 兩者恰好都是以 res 為前綴,只要命名為res就天下太平了——才怪。

有什麼比 result 更讓人想握緊拳頭的變數名稱嗎?恐怕就是 res 了。


小結:No result

總的來說,data 至少還有適用的例外情況,但 result,我真的想不到。

我非常確信,打從我轉職後工作的第二年起(第一年還懵懂無知),再就也沒有使用過 result 這個變數名稱。

一次也沒有。