我有一个嵌套函数,我试图访问父作用域中分配的变量。从next()
函数的第一行开始,我可以看到path
和nodes_done
按预期分配。 distance
,current
和probability_left
没有任何价值,导致NameError
被抛出。
我在这里做错了什么?如何从current
函数访问和修改distance
,probability_left
和next()
的值?
def cheapest_path(self):
path = []
current = 0
distance = 0
nodes_done = [False for _ in range(len(self.graph.nodes))]
probability_left = sum(self.graph.probabilities)
def next(dest):
log('next: %s -> %s distance(%.2f), nodes_done(%s), probability_left(%.2f)' % (distance,self.graph.nodes[current],self.graph.nodes[dest],str(nodes_done),probability_left))
path.append((current, distance, nodes_done, probability_left))
probability_left -= self.graph.probabilities[current]
nodes_done[current] = True
distance = self.graph.shortest_path[current][dest]
current = dest
def back():
current,nodes_done,probability_left = path.pop()
答案 0 :(得分:4)
Python的嵌套作用域的工作方式,您永远不能将分配给父作用域中的变量,除非它是全局的(通过global
关键字)。这在Python 3中发生了变化(增加了nonlocal
),但是在2.x中你被卡住了。
相反,您必须使用通过引用存储的数据类型来解决此问题:
def A():
foo = [1]
def B():
foo[0] = 2 # since foo is a list, modifying it here modifies the referenced list
请注意,这就是您的列表变量有效的原因 - 它们通过引用存储,因此修改列表会修改原始引用列表。如果您尝试在嵌套函数中执行path = []
之类的操作,那么它将无效,因为它实际上会分配给path
(Python会将其解释为创建新的局部变量path
在阴影父项path
)的嵌套函数中。
有时使用的一个选项是将您想要保留的所有内容保留在dict
的嵌套范围中:
def A():
state = {
'path': [],
'current': 0,
# ...
}
def B():
state['current'] = 3
答案 1 :(得分:2)
简短的回答是python没有适当的词法范围支持。如果确实如此,则必须有更多语法来支持该行为(即var / def / my关键字以声明变量范围)。
除了实际的词法范围,您可以做的最好的事情是将数据存储在环境数据结构中。一个简单的例子是列表,例如:
def cheapest_path(self):
path = []
path_info = [0, 0]
nodes_done = [False for _ in range(len(self.graph.nodes))]
probability_left = sum(self.graph.probabilities)
def next(dest):
distance, current = path_info
log('next: %s -> %s distance(%.2f), nodes_done(%s), probability_left(%.2f)' % (distance,self.graph.nodes[current],self.graph.nodes[dest],str(nodes_done),probability_left))
path.append((current, distance, nodes_done, probability_left))
probability_left -= self.graph.probabilities[current]
nodes_done[current] = True
path_info[0] = self.graph.shortest_path[current][dest]
path_info[1] = dest
def back():
current,nodes_done,probability_left = path.pop()
你可以这样做或者检查魔法。有关此更多历史,请阅读此thread。
答案 2 :(得分:2)
如果您正在使用Python 3,则可以使用nonlocal
语句(documentation)使这些变量存在于当前范围内,例如:
def next(dest):
nonlocal distance, current, probability_left
...