Python闭包中的数值变量范围(Python v2.5.2)
我有一个嵌套函数,试图访问在父作用域中分配的变量。从Python闭包中的数值变量范围(Python v2.5.2),python,Python,我有一个嵌套函数,试图访问在父作用域中分配的变量。从next()函数的第一行,我可以看到path和节点\u done按预期分配距离、当前和左概率没有值,导致抛出名称错误 我做错了什么?如何从next()函数访问和修改current、distance和probability\u left的值 def cheapest_path(self): path = [] current = 0 distance = 0 nodes_done = [False for _ in
next()
函数的第一行,我可以看到path
和节点\u done
按预期分配<代码>距离、当前
和左概率
没有值,导致抛出名称错误
我做错了什么?如何从next()
函数访问和修改current
、distance
和probability\u left
的值
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()
按照Python嵌套作用域的工作方式,您永远不能将变量赋值给父作用域中的变量,除非它是全局变量(通过
global
关键字)。这在Python3中发生了变化(添加了非本地的
),但在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
,该嵌套函数会隐藏父函数的路径
)
有时使用的一个选项是将所有要持久化的内容保留在dict
中的嵌套范围中:
def A():
state = {
'path': [],
'current': 0,
# ...
}
def B():
state['current'] = 3
简而言之,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()
你可以这样做,也可以检查魔法。有关此操作的更多历史信息,请阅读此内容。如果您碰巧正在使用Python 3,则可以使用
非本地
语句()使这些变量存在于当前范围中,例如:
def next(dest):
nonlocal distance, current, probability_left
...
+1.在这种情况下,为了清楚起见,我建议使用一个
dict
,而不是一个列表。@Cameron我实际上只是添加了一个注释:PI认为可能是这样的,但要确保我没有遗漏语言中的某些内容这是不正确的:nonlocal
关键字允许在外部但非全局范围内写入变量。不幸的是,它只在Python3中可用,这有点令人费解,因为我认为这纯粹是一个语法问题,甚至不需要额外的VM支持;但它就在那里。它确实需要向后移植到2.x,因为在大多数人使用3.x之前还需要几年时间;因此,给出适用于该版本的答案通常是有意义的。您还需要修改probability\u left
。此外,最好使用dict
而不是列表,因为[0]
和[1]
的描述性远远低于['current']
和['distance']
。