簡體   English   中英

python 中帶有條件返回的功能樣式

[英]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構造,或隱式等價物,或任何類似progprog1的表親。 Lisp 中的函數 function 總是有一個由單個表達式(或者可能根本沒有表達式)組成的主體。

您可以在 Python 中重新定義“功能編碼”的含義。 這些規則怎么樣:

  1. “功能函數”中的每條語句都必須是一條語句; 它后面不能有另一個語句。 因此,function 的整個主體是單個語句,其中嵌入了單個語句。

  2. function 中的任何語句都不允許控制通過它。 每個語句都必須返回。 因此, return不僅被認為是“功能性的”,而且對於實現這一目標至關重要。

  3. 變量可以定義,但不能重新定義。 並行的、互斥的控制流可以為同一變量分配不同的值,但在同一控制流中不能多次分配變量。

使用這些規則,您可以讓程序擁有一個類似於純 Lisp 風格的程序的控制流圖:控制圖基本上是一棵具有嵌入式計算和變量綁定的決策樹,其葉子是要返回的值。

說到變量綁定,我們大概應該有第四條規則:

  1. 一條語句前面可能有一系列不包含副作用的新變量賦值。 這樣一個序列,連同它后面的語句,算作一個語句。

可以說也是第五個:

  1. 不得使用對任何包含的表達式或語句進行多次評估的語句。

否則,我們允許沒有功能的循環。 這很棘手,因為一些循環結構的行為相對良好,例如隱式地將虛擬變量跨過列表的元素。 您可以判斷它不起作用的唯一方法是,在循環中捕獲的詞法閉包很容易顯示只有一個變量被變異,而不是每次迭代都綁定一個新變量。

根據這些規則, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM