帖子内容
Python 有一个 context manager 的概念,可以用来保证退出某个文法上下文时一定释放某个资源: with open('foo') as f: print(f.read()) 其原理是 with 语句在进入时调用 f.__enter__,如果成功,保证在退出时调用 f.__exit__。 类似地,Haskell 中有 bracket pattern 的概念: withFile "foo" ReadMode (\f -> do content <- hGetContents f putStr content) 其原理是构造了一个接受 f 的函数,表示 with 内要做的事情,把它传给 withFile,由 withFile 调用,并保证退出时关闭文件。 这两种设计有一个很大的区别:能否容易地写出一个安全的 context manager,它“包装”其他一些 context manager,保证每一层的语义都正确?Python 这样写是不对的: class Outer: def __init__(self): self.inner1 = Inner1() self.inner2 = Inner2() def __enter__(self): self.inner1.__enter__() self.inner2.__enter__() def __exit__(self, *exc): self.inner2.__exit__(*exc) self.inner1.__exit__(*exc) 因为如果 inner2.__enter__() 出错,inner1 将不会被关闭。如果想要写得安全的话,不应该手工调用 inner 的 __enter__ 和 __exit__,而应该利用绝对安全的 with 语句来管理 inner。但 __enter__ 和 __exit__ 是两个不同的函数,没法跨越文法上下文的边界使用 with 语句。 Haskell 的 bracket 风格的函数就很简单了,可以直接套起来: withOuter action = withInner1 (\a -> withInner2 (\b -> action a b))