回调闭包中的未来证明范围[Python]

时间:2016-10-25 18:37:36

标签: python callback closures scoping

我们通常很熟悉Python中的这个“陷阱”,因为它的范围很广:

functions = []
for i in range(3):
    functions.append(lambda : i)

out = [f() for f in functions]

# naive expectation = [0, 1, 2]
# actual result = [2, 2, 2]

我们通常熟悉如何符合我们的期望:

    functions.append(lambda i=i: i)

然而,在尝试创建“面向未来”的回调闭包时,我遇到了一个问题,即扩展回调签名的可能性会破坏用于定义闭包范围的默认参数。

考虑这种情况:

def old_style_callback(data, *args, **kwargs):
    # ...

# define a bunch of closures
closures = []
for cb in list_of_callbacks:
    def old_style_closure(data, callback=cb, *args, **kwargs):
        cb(data, *args, **kwargs)
        # ...
    closures.append(old_style_closure)

但是如果你需要添加一个容纳一些新功能的新参数呢?

def new_style_callback(data, metadata, *args, **kwargs):
    # ...

现在你的old_style_closure已被破坏,因为metadata将被传递给你用来扩展闭包范围并访问回调的默认参数!

似乎你想要“未来证明”的回调闭包,你被迫坚持你的原始签名,并通过这些论点传递一切。这并不是那么糟糕,但是如果你没有让你的原始签名足够通用,这就会出现问题。

对此问题的任何想法或新方法表示赞赏。

1 个答案:

答案 0 :(得分:0)

在写完这个问题后,我意识到你可以通过创建一个新的函数来解决这个问题,用拥有范围来创建闭包。一旦你拥有了它,你只需在循环中调用它:

def create_callback_closure(callback):
    def old_style_closure(data, *args, **kwargs):
        callback(data, *args, **kwargs)
        # ...

closures = []
for cb in list_of_callbacks:
    closures.append(create_callback_closure(callback))