我正在编写一个带有此函数的图形遍历脚本,它将一个映射函数作为参数应用于每个顶点,但由于Python没有指针,因此无法弄清楚如何共享闭包:
def walk_vertices(graph, function, closure):
for vertex in graph.vertices:
function(vertex, closure)
return closure
例如,这可用于总结整数顶点的值,而在基于C的语言中,闭包将是指向运行总和的指针。在Python中实现这个的好方法是什么?感谢。
答案 0 :(得分:1)
实际上我认为语言是python或java只是指向对象的指针。
虽然函数无法重新绑定到walk_vertices中的对象闭包'points',但如果对象闭包'指向'是可变的,它当然可以改变它。在你的例子中,你谈论一个总和。那当然是整数或浮点数。这些在python中是不可变的,所以闭包会指向一个对象,但你不能改变它:
x = 5
def something(ref):
# you can't change where x points to from here.
# and because an int is immutable you can't change it.
ref = 10 # rebinds ref, but not x
something(x)
print(x) # still 5
但是,如果你传递一个可变对象,你实际上可以存储信息。拥有一个非常简单的可变对象的一种方法就是使用大小为1的列表。
x = [5]
def something(ref):
# you can't change where x points to from here.
ref = 5 # rebinds ref, but not x
something(x)
print(x) # still [5]
def something2(ref):
# ref is a mutable object, so
ref[0] = 10 # ref points to the same list, but contents of list is now 10
something2(x)
print(x) # now [10]
相同的构造适用于任何可变对象。所以也可以使用词典或类。
class EmptyClass:
pass
x = EmptyClass()
x.data = 5
def something(ref):
ref.data = 10
something(x)
print(x.data) # now prints 10
总而言之,python总是传递与指针相当的东西。但是因为它有一些不可变的类型,所以你不能总是使用它来传回数据。你必须传递一个可变对象。
python也没有相当于获取局部变量的指针。因此,虽然一切都是指向对象的指针,但是如果没有像列表情况(指向列表的指针)之间的对象,则无法获得指向指针的指针。 您可以做的是使用'reflection'通过locals()
更改局部变量的值x = 5
def something(d):
d['x'] = 10
something(locals())
print(x) # now prints 10
答案 1 :(得分:0)
不清楚"关闭"的含义。如果您只是希望回调能够在调用之间保持状态,那么有很多方法可以做到这一点,例如在函数编程意义上使用closures:
def walk_vertices(graph, callback):
...
def f(graph):
running_sum = 0
def callback(vertex):
# Python 3 only
nonlocal running_sum
running_sum += vertex.value
walk_vertices(graph, callback)
return running_sum
def python2f(graph):
running_sum = [0]
def callback(vertex):
# awkward hack
running_sum[0] += vertex.value
walk_vertices(graph, callback)
return running_sum[0]
但我认为最自然的方式是使用发电机。而不是walk_vertices
遍历图表并对每个顶点应用回调,而是yield
s每个顶点。然后调用代码可以使用普通循环遍历顶点,而无需编写笨拙的回调:
def walk_vertices(graph):
# Pretend generating vertices is more complicated than this:
for vertex in graph.vertices:
yield vertex
running_sum = 0
for v in walk_vertices(graph):
running_sum += v.value
# or just
vertex_sum = sum(v.value for v in walk_vertices(graph))