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

Future Proof Scoping In Callback Closures [Python]

由于范围界定,我们通常熟悉 Python 中的 "gotcha":

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)

但是,在尝试创建 "future proof" 回调闭包时,我 运行 遇到了一个问题,扩展回调签名的可能性会破坏用于定义回调函数范围的默认参数关闭。


考虑这个案例:

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 将传递给您用于扩展闭包范围和访问回调的默认参数!


似乎如果您想要 "future proof" 回调闭包,您将被迫坚持使用您的原始签名并通过这些参数传递所有内容。这并没有那么糟糕,但是如果您没有使您的原始签名足够通用,这就会出现问题。

任何解决此问题的想法或新方法都将受到赞赏。

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

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