[英]Functional style with conditional returns in python
假設我們有一個具有以下結構的 function:
def f():
# ...
# some computations
# ...
if something_is_wrong_with_previous_computations:
return None
# ...
# some other computations
# ...
if something_is_wrong_with_previous_computations2:
return some_variable
#...
return result
如我所見,在 function 中間使用return
語句根本不起作用。 如果我們使用某種 lispy 語言,我們將使用let
(然后可以用let*
編寫計算)語句,這將幫助我們輕松處理這些情況。 不幸的是,我們這里沒有。 我們應該做什么?
let
創建大量嵌套函數並就地調用它們?Maybe
monad 之類的東西或其他類似的復雜東西? function 中任何地方的return
語句都不起作用。
在 Python 中,您別無選擇。
Lisp 代碼
(defun sgnum (x)
(cond
((< x 0) -1)
((zerop x) 0)
(t 1)))
變成 Python 為
def sgnum(x):
if x < 0:
return -1
elif x == 0:
return 0
else:
return 1
在 Lisp 中,當我們使用變量賦值或“程序特性”時,我們知道我們已經偏離了函數式編碼:顯式progn
構造,或隱式等價物,或任何類似prog
或prog1
的表親。 Lisp 中的函數 function 總是有一個由單個表達式(或者可能根本沒有表達式)組成的主體。
您可以在 Python 中重新定義“功能編碼”的含義。 這些規則怎么樣:
“功能函數”中的每條語句都必須是一條語句; 它后面不能有另一個語句。 因此,function 的整個主體是單個語句,其中嵌入了單個語句。
function 中的任何語句都不允許控制通過它。 每個語句都必須返回。 因此, return
不僅被認為是“功能性的”,而且對於實現這一目標至關重要。
變量可以定義,但不能重新定義。 並行的、互斥的控制流可以為同一變量分配不同的值,但在同一控制流中不能多次分配變量。
使用這些規則,您可以讓程序擁有一個類似於純 Lisp 風格的程序的控制流圖:控制圖基本上是一棵具有嵌入式計算和變量綁定的決策樹,其葉子是要返回的值。
說到變量綁定,我們大概應該有第四條規則:
可以說也是第五個:
否則,我們允許沒有功能的循環。 這很棘手,因為一些循環結構的行為相對良好,例如隱式地將虛擬變量跨過列表的元素。 您可以判斷它不起作用的唯一方法是,在循環中捕獲的詞法閉包很容易顯示只有一個變量被變異,而不是每次迭代都綁定一個新變量。
根據這些規則, sgnum
是“功能性的”:它只包含一個if/elif/else
語句,不允許控制通過它:每個分支都返回:
這個版本的sgnum
是“功能性的”:
def sgnum(x):
if x < 0:
return -1
if x == 0:
return 0
return 1
它依次包含三個語句。 而以下是“功能性的”,即使它也包含三個語句:
def distance(x0, y0, x1, y1):
xd = x1 - x0
yd = y1 - y0
return math.sqrt(xd * xd + yd * yd)
這些符合規則。 前兩個語句綁定新變量,符合規則 3,因此 4 允許在語句之前。 return 語句符合規則 1 和 2。這非常類似於:
(defun distance (x0 y0 x1 y1)
(let ((xd (- x1 x0))
(yd (- y1 y0)))
(sqrt (+ (* xd xd) (* yd yd)))))
最后,請注意我們的規則與“函數中只有一個出口點”的古老編程建議有何不同。 您可能在某些編碼約定中發現的那個小花絮是相當反功能的。 為了在不平凡的 function 中實現單點返回,需要通過多個語句和/或變量賦值的命令式控制流。 從功能上看,這是一條短視的、愚蠢的規則; 但在推薦它的上下文中它是有意義的,因為它可以幫助改進結構非常糟糕的命令式代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.