在Python中的映射函数实例之间共享数据

时间:2015-06-11 20:27:42

标签: python

我正在编写一个带有此函数的图形遍历脚本,它将一个映射函数作为参数应用于每个顶点,但由于Python没有指针,因此无法弄清楚如何共享闭包:

def walk_vertices(graph, function, closure):
    for vertex in graph.vertices:
        function(vertex, closure)
    return closure
例如,这可用于总结整数顶点的值,而在基于C的语言中,闭包将是指向运行总和的指针。在Python中实现这个的好方法是什么?感谢。

2 个答案:

答案 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遍历图表并对每个顶点应用回调,而是yields每个顶点。然后调用代码可以使用普通循环遍历顶点,而无需编写笨拙的回调:

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))