簡體   English   中英

Python什么時候用嵌套函數好?

[英]When is it good to use nested functions in Python?

我不是指閉包,其中外部 function 返回內部 function,或者特別是記憶。 有幾個例子我想寫一個遞歸的 function,也許有記憶,在外部 function 中初始化一個字典或一些其他數據結構似乎更簡單,然后有一個遞歸助手 function 寫入和訪問字典和外部 function 的 arguments。這就是我的意思——

def foo(arr, l):
   cache = {}
   result = []

   def recursive_foo_helper(i, j, k):
      # some code that depends on arr, l, i, j, k, cache, and result

   for (x, y) in arr:
      if recursive_foo_helper(x, y, k):
         return result
   return None

而不是用一些超長簽名單獨聲明 helper function,例如,

recursive_foo_helper(arr, l, i, j, k, cache={}, result=[])

我讀過這樣做是記憶化的標准,但我很好奇是否就是否可以僅對遞歸輔助函數執行此操作達成共識。

有很多好的理由。 就個人而言,我經常使用嵌套函數來保持命名空間的整潔。 它在對象方法中特別有用:

class Foo(object):
    def bar(self):
        def baz(val):
            return val
        return [ baz(i) for i in range(1,101) ]

如果我在bar之外聲明baz ,我要么需要將其設為Foo的方法,要么將其公開給整個包。

我使用嵌套函數從列表中查找匹配項:

def get_exact(data, key, match):
    def is_match(item):
        if (key in item) and (item[key].lower() == match.lower()):
            return item
        return False
    return [i for i in data if is_match(i)]

項目中沒有其他調用需要使用is_match(item) ,那么為什么要單獨聲明呢?

但是,我會說,對於我的示例,在get_exact() is_match()在 10,000 次迭代中運行速度確實快了約 0.04 秒

def is_match(item, key, match):
    if (key in item) and (item[key].lower() == match.lower()):
        return item
    return False

def get_exact(data, key, match):
    return [i for i in data if is_match(i, key, match)]

我通常使用閉包,但是您建議的另一種方式(我有時稱為 Wrapper)也非常有用,並且根據我的個人經驗,它可以正常工作。 我從來沒有人告訴我要避免這種風格。 如果您的代碼有效並且可讀(我認為是這樣),那就去吧!

我想說使用你建議的閉包更干凈,但如果你想重新綁定引用,確實需要nonlocal中的 nonlocal 關鍵字。 對於可變對象,顯然可以修改它們。

同時,在 Python2 中看到 defaultarg hacks/idioms 是很常見的

嵌套函數的一個(也許是唯一的)缺點是難以進行單元測試。

為了確保緩存不會無限增長,您還需要一種刪除項目的方法(例如最近最少使用的)

我認為嵌套函數非常適合遞歸。 考慮以下函數來搜索 BST 是否包含具有數據target的節點:

def contains_target(self, target) -> bool:
        def _contains_target(node, target):
            if node is not None:
                found = False
                found = _contains_target(node.left, target)
                if found:
                    return True
                found = _contains_target(node.right, target)
                if found:
                    return True
                found = target == node.data
                return found
            else:
                return False

        # Begin at the root
        return _contains_target(self.root, target)

我發現這更可取,因為當第一次運行嵌入式輔助函數時,您可以為一個或所有參數設置一個初始化參數。 在這種情況下,考慮的第一個節點是樹的根節點。

嵌套函數的一個缺點是在測試方面。

def compute_sequence(sequence):
    """Compute blabla on sequence"""

    def compute_element(element):
        """Compute blabla on element"""
        return element * 2

    sequence = sequence + 1  # global treatment
    return [compute_element(element) for element in sequence]

問題:如何測試 compute_element? 你如何訪問它的文檔字符串?

意見:如果您選中“導入此”,您將看到:

Python 的 Zen,作者 Tim Peters [...] Flat 優於嵌套。 [...]

即使我今天大量使用嵌套函數,我也覺得使用它們很不自在 Peace out

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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