[英]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'})})
有兩點需要注意:
lambda
代表一個匿名函數。 所以這里有兩種不同的方法來定義功能相同的對象。 它們是遞歸函數,因為它們引用自己。
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.