不理解这个带有 defaultdict 的 lambda 表达式
don't understand this lambda expression with defaultdict
我在 pythontips 上看到了这个例子。当 defaultdict 接受参数 "tree" 和 return a "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'})})
如果您尝试这样做会更容易看到:a = lambda: a
,您会看到 a()
returns 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
注意两点:
lambda
代表一个匿名函数。
- 函数是 Python 中的第一个 class 个对象。它们可以像任何其他对象一样分配给变量。
所以这里有两种不同的方法来定义功能相同的对象。它们是递归函数,因为它们引用自己。
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
,returns一个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
我希望这能解决问题![=31=]
我在 pythontips 上看到了这个例子。当 defaultdict 接受参数 "tree" 和 return a "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'})})
如果您尝试这样做会更容易看到:a = lambda: a
,您会看到 a()
returns 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
注意两点:
lambda
代表一个匿名函数。- 函数是 Python 中的第一个 class 个对象。它们可以像任何其他对象一样分配给变量。
所以这里有两种不同的方法来定义功能相同的对象。它们是递归函数,因为它们引用自己。
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
,returns一个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
我希望这能解决问题![=31=]