我在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'})})
答案 0 :(得分:3)
注意两点:
lambda
代表一个匿名函数。因此,这里有2种不同的方法来定义功能相同的对象。它们是递归函数,因为它们引用了自己。
from collections import defaultdict
# anonymous
tree = lambda: defaultdict(tree)
# explicit
def tree(): return defaultdict(tree)
依次使用这些不同的定义运行最后两行,您会发现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'})})
答案 1 :(得分:1)
看是否尝试这样做更容易:a = lambda: a
,您会看到a()
返回a
。所以...
>>> a = lambda: a
>>> a()()()()
<function <lambda> at 0x102bffd08>
他们也使用defaultdict
进行此操作。 tree
是一个返回defaultdict的函数,其默认值为另一个defaultdict,依此类推。
我实际上也没有意识到这一点。我认为tree
必须先定义。也许这是一条特殊的Python规则? (编辑:)不,我忘记了Python在运行时进行名称查找,然后tree
便指向了lambda。在C ++中,有编译时引用检查,但是您可以定义引用自己的函数。
这似乎是一种创建某些用户无法预期的行为的方法。就像说您不小心在以后重新定义tree
一样,您的defaultdict被破坏了:
>>> 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
答案 2 :(得分:1)
这是创建递归defaultdict
的非常聪明的方法。刚开始理解时会有些棘手,但是一旦您深入了解正在发生的事情,实际上就是一种非常简单的递归用法。
在此示例中,我们定义了一个递归lambda函数tree
,该函数返回其构造函数为defaultdict
的{{1}}。为了清楚起见,让我们使用常规函数重写它。
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>, {})})
我希望这可以解决所有问题!