class 从封闭范围获取 kwargs
class getting kwargs from enclosing scope
Python 似乎从 class 方法的封闭范围中推断出一些 kwargs,我不确定为什么。我正在实施 Trie:
class TrieNode(object):
def __init__(self, value = None, children = {}):
self.children = children
self.value = value
def __getitem__(self, key):
if key == "":
return self.value
return self.children[key[0]].__getitem__(key[1:])
def __setitem__(self, key, value):
if key == "":
self.value = value
return
if key[0] not in self.children:
self.children[key[0]] = TrieNode()
self.children[key[0]].__setitem__(key[1:], value)
在倒数第二行,我创建了一个新的 TrieNode,大概是一个空的子字典。但是,当我检查生成的数据结构时,树中的所有 TrieNode 都使用相同的子字典。即,如果我们这样做:
>>>test = TrieNode()
>>>test["pickle"] = 5
>>>test.children.keys()
['c', 'e', 'i', 'k', 'l', 'p']
而 test 的子节点应该只包含 "p" 指向一个新的 TrieNode。另一方面,如果我们进入该代码的倒数第二行并将其替换为:
self.children[key[0]] = TrieNode(children = {})
然后它按预期工作。那么,不知何故,self.children 字典作为 kwarg 隐式传递给 TrieNode(),但为什么呢?
您遇到了 mutable default argument 问题。将你的 __init__
函数改成这样
def __init__(self, value=None, children=None):
if not children:
children = {}
children 的默认值只会在函数创建时计算一次,而您希望它在每次调用时都是一个新的字典。
这是一个使用列表的问题的简单示例
>>> def f(seq=[]):
... seq.append('x') #append one 'x' to the argument
... print(seq) # print it
>>> f() # as expected
['x']
>>> f() # but this appends 'x' to the same list
['x', 'x']
>>> f() # again it grows
['x', 'x', 'x']
>>> f()
['x', 'x', 'x', 'x']
>>> f()
['x', 'x', 'x', 'x', 'x']
正如我链接到的答案所描述的那样,这最终会影响每个 python 程序员。
您遇到的行为来自以下行:
def __init__(self, value = None, children = {}):
children = {}
被称为mutable default argument。在这种情况下,默认参数是在函数定义上一次构造的,每次修改都会影响以后的每个函数调用(使用默认值)。
要解决此问题,您应该将 None
作为默认值传递(因为 None
不可变,上述行为不适用):
def __init__(self, value = None, children = None):
self.children = children if children else {}
self.value = value
Python 似乎从 class 方法的封闭范围中推断出一些 kwargs,我不确定为什么。我正在实施 Trie:
class TrieNode(object):
def __init__(self, value = None, children = {}):
self.children = children
self.value = value
def __getitem__(self, key):
if key == "":
return self.value
return self.children[key[0]].__getitem__(key[1:])
def __setitem__(self, key, value):
if key == "":
self.value = value
return
if key[0] not in self.children:
self.children[key[0]] = TrieNode()
self.children[key[0]].__setitem__(key[1:], value)
在倒数第二行,我创建了一个新的 TrieNode,大概是一个空的子字典。但是,当我检查生成的数据结构时,树中的所有 TrieNode 都使用相同的子字典。即,如果我们这样做:
>>>test = TrieNode()
>>>test["pickle"] = 5
>>>test.children.keys()
['c', 'e', 'i', 'k', 'l', 'p']
而 test 的子节点应该只包含 "p" 指向一个新的 TrieNode。另一方面,如果我们进入该代码的倒数第二行并将其替换为:
self.children[key[0]] = TrieNode(children = {})
然后它按预期工作。那么,不知何故,self.children 字典作为 kwarg 隐式传递给 TrieNode(),但为什么呢?
您遇到了 mutable default argument 问题。将你的 __init__
函数改成这样
def __init__(self, value=None, children=None):
if not children:
children = {}
children 的默认值只会在函数创建时计算一次,而您希望它在每次调用时都是一个新的字典。
这是一个使用列表的问题的简单示例
>>> def f(seq=[]):
... seq.append('x') #append one 'x' to the argument
... print(seq) # print it
>>> f() # as expected
['x']
>>> f() # but this appends 'x' to the same list
['x', 'x']
>>> f() # again it grows
['x', 'x', 'x']
>>> f()
['x', 'x', 'x', 'x']
>>> f()
['x', 'x', 'x', 'x', 'x']
正如我链接到的答案所描述的那样,这最终会影响每个 python 程序员。
您遇到的行为来自以下行:
def __init__(self, value = None, children = {}):
children = {}
被称为mutable default argument。在这种情况下,默认参数是在函数定义上一次构造的,每次修改都会影响以后的每个函数调用(使用默认值)。
要解决此问题,您应该将 None
作为默认值传递(因为 None
不可变,上述行为不适用):
def __init__(self, value = None, children = None):
self.children = children if children else {}
self.value = value