首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何判断上下文管理器是可重用的还是可重入的?

如何判断上下文管理器是可重用的还是可重入的?
EN

Stack Overflow用户
提问于 2014-07-30 19:31:17
回答 1查看 2.4K关注 0票数 12

Python指出,上下文管理器可以是单一用途、可重用或可重入的。可重入语句可以用于多个with语句,包括嵌套语句;可重用但不能重入的语句可以用于多个with语句,而不是嵌套语句。这里提到了几个例子。

https://docs.python.org/3/library/contextlib.html#reentrant-context-managers

不过,其他上下文管理器的文档并不总是提到它们是什么。例如,patch上下文管理器在unittest.mock中的文档根本没有提到这一点。

通常,您会在源代码中查看哪些内容来确定上下文管理器是单一用途、可重用还是可重入?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-07-30 20:00:30

一种好的方法是查看由__enter__调用返回/修改的对象或设置的上下文,然后查看__exit__调用中对象/上下文发生了什么变化。通常,了解状态是如何在每一种状态中被改变的,就会清楚地知道,如果你嵌套或重复使用该对象,将会发生什么。

例如,当您with open("somefile") as f:时,您将得到一个文件句柄。在__exit__中,您将关闭该文件句柄。当然,关闭后重新打开文件句柄对象是没有意义的,打开已经打开的文件句柄也没有意义。当然,关闭内部文件句柄也会关闭外部文件句柄,这将是一个问题。这就是为什么从来没有人这样做:

代码语言:javascript
复制
f = open("file.txt")
with f:
  # stuff
# File will get closed here

关闭f之后使用它是没有意义的,所以我们总是使用:

代码语言:javascript
复制
with open("file.txt") as f:

threading.Lockthreading.RLock对象也可以用作上下文管理器。这样做是有道理的:

代码语言:javascript
复制
l = threading.Lock()
with l: # This acquires the lock
    # stuff
# Lock got released

with l: # Acquired again
    # more stuff
# Released again

这并不是这样,因为如果您尝试递归地使用它,Lock将陷入死锁。

代码语言:javascript
复制
l = threading.Lock()
with l:
    #  stuff
    with l: # Uh-oh, we tried acquiring an already acquired Lock. We'll deadlock here.

但是,这将很好地适用于RLock(),它可以递归地获得。

stdlib中的另一个示例:multiprocessing.Pool()可以用作Python中的上下文管理器。医生们是这么说的:

池对象现在支持上下文管理器协议。__enter__()返回池对象,__exit__()调用terminate()

terminate()说它这样做:

在未完成未完成的工作的情况下立即停止工作人员处理。当池对象被垃圾收集时,会立即调用terminate()。

很明显,这是一次性使用。

patch上下文管理器暂时对某个对象进行修补,然后在完成修补程序时撤消修补程序。嵌套绝对没有意义-你为什么要重新修补已经修补好的东西?但是,修补、取消修补,然后再进行修补在逻辑上是有意义的,因此它应该是可重用的(测试就是这样)。

我不认为有任何定义明确的东西,你可以说“寻找这个,你就会知道上下文管理器是可重用的/可重用的/一次性的”,因为上下文管理器可以做任何事情。您能做的最好的事情就是了解在__enter__中建立什么上下文,如何分解__exit__,然后逻辑地确定重用/重新输入上下文的含义。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25045379

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档