簡體   English   中英

用defaultdict不理解這個lambda表達式

[英]don't understand this lambda expression with defaultdict

我在pythontips看到了這個例子。 當defaultdict接受參數“tree”並返回“tree”時,我不明白第二行。

import collections
tree = lambda: collections.defaultdict(tree)
some_dict = tree()
some_dict['color']['favor'] = "yellow"
# Works fine

運行此代碼后,我檢查了some_dict的類型

defaultdict(< function < lambda > at 0x7f19ae634048 >, 
            {'color': defaultdict(
                  < function < lambda > at 0x7f19ae634048 >, {'favor': 'yellow'})})

有兩點需要注意:

  1. lambda代表一個匿名函數。
  2. 函數是Python中的第一類對象。 它們可以像任何其他對象一樣分配給變量。

所以這里有兩種不同的方法來定義功能相同的對象。 它們是遞歸函數,因為它們引用自己。

from collections import defaultdict

# anonymous
tree = lambda: defaultdict(tree)

# explicit
def tree(): return defaultdict(tree)

依次運行具有這些不同定義的最后2行,您只能看到defaultdict類型命名的細微差別:

# anonymous
defaultdict(<function __main__.<lambda>()>,
            {'color': defaultdict(<function __main__.<lambda>()>,
                         {'favor': 'yellow'})})

# explicit
defaultdict(<function __main__.tree()>,
            {'color': defaultdict(<function __main__.tree()>,
                         {'favor': 'yellow'})})

這是創建遞歸defaultdict一種非常聰明的方法。 一開始理解起來有點棘手,但是一旦你深入了解正在發生的事情,它實際上是一個非常簡單的遞歸使用。

在這個例子中,我們定義了一個遞歸的lambda函數tree ,它返回一個defaultdict其構造函數是tree 為清晰起見,我們使用常規函數重寫它。

from collections import defaultdict
from pprint import pprint

def get_recursive_dict():
    return defaultdict(get_recursive_dict)

請注意,我們返回defaultdict(get_recursive_dict)而不是defaultdict(get_recursive_dict()) 我們想要將defaultdict傳遞給一個可調用對象(即函數get_recursive_dict )。 實際上調用get_recursive_dict()會導致無限遞歸。

如果我們調用get_recursive_dict ,我們得到一個空的defaultdict其默認值是函數get_recursive_dict

recursive_dict = get_recursive_dict()
print(recursive_dict)
# defaultdict(<function get_recursive_dict at 0x0000000004FFC4A8>, {})

讓我們看看這個在行動。 創建密鑰'alice' ,它的相應值默認為空defaultdict其默認值為函數get_recursive_dict 請注意,這與recursive_dict默認值相同!

print(recursive_dict['alice'])
# defaultdict(<function get_recursive_dict at 0x0000000004AF46D8>, {})
print(recursive_dict)
# defaultdict(<function get_recursive_dict at 0x0000000004AF46D8>, {'alice': defaultdict(<function get_recursive_dict at 0x0000000004AF46D8>, {})})

因此,我們可以根據需要創建盡可能多的嵌套字典。

recursive_dict['bob']['age'] = 2
recursive_dict['charlie']['food']['dessert'] = 'cake'
print(recursive_dict)
# defaultdict(<function get_recursive_dict at 0x00000000049BD4A8>, {'charlie': defaultdict(<function get_recursive_dict at 0x00000000049BD4A8>, {'food': defaultdict(<function get_recursive_dict at 0x00000000049BD4A8>, {'dessert': 'cake'})}), 'bob': defaultdict(<function get_recursive_dict at 0x00000000049BD4A8>, {'age': 2}), 'alice': defaultdict(<function get_recursive_dict at 0x00000000049BD4A8>, {})})

使用鍵覆蓋默認值后,您將無法再創建任意深度嵌套的詞典。

recursive_dict['bob']['age']['year'] = 2016
# TypeError: 'int' object does not support item assignment

我希望這能解決問題!

你是否更容易看到: a = lambda: a ,你會看到a()返回a 所以...

>>> a = lambda: a
>>> a()()()()
<function <lambda> at 0x102bffd08>

他們也使用defaultdict這樣做。 tree是一個返回defaultdict的函數,其默認值是另一個defaultdict,依此類推。

我其實也沒有意識到這一點。 我認為必須首先定義tree 也許這是一個特殊的Python規則? (編輯:)不,我忘了Python在運行時進行名稱查找,然后tree已經指向lambda。 在C ++中有編譯時引用檢查,但您可以定義引用自身的函數。

這似乎是一種創建某些用戶不會期望的行為的方法。 就像說你以后意外重新定義tree一樣,你的默認指令被破壞了:

>>> import collections
>>> tree = lambda: collections.defaultdict(tree)
>>> some_dict = tree()
>>> tree = 4
>>> some_dict[4][3] = 2 # TypeError: first argument must be callable or None

暫無
暫無

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

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