Python 类实例中的上下文管理器
我想创建一个特定于另一个类实例的上下文管理器类。我可以通过调用创建类的方法来实现这一点,但我不确定这是最好、最好的方法:Python 类实例中的上下文管理器,python,Python,我想创建一个特定于另一个类实例的上下文管理器类。我可以通过调用创建类的方法来实现这一点,但我不确定这是最好、最好的方法: class MyClass(object): def __init__(self): self.level = 0 self.Nest = self.create_context_manager() def inclev(self): self.level += 1 def declev(self):
class MyClass(object):
def __init__(self):
self.level = 0
self.Nest = self.create_context_manager()
def inclev(self):
self.level += 1
def declev(self):
self.level -= 1
def create_context_manager(self):
self2 = self
class Nest(object):
def __init__(self):
pass
def __enter__(self):
self2.inclev()
def __exit__(self, exc_type, exc_value, traceback):
self2.declev()
return Nest
# Manually increase/decrease level
my_instance = MyClass()
print(my_instance.level)
my_instance.inclev()
print(my_instance.level)
my_instance.inclev()
print(my_instance.level)
my_instance.declev()
print(my_instance.level)
my_instance.declev()
print(my_instance.level)
# Use instance-specific context manager
other_instance = MyClass()
print(other_instance.level)
with other_instance.Nest():
print(other_instance.level)
with other_instance.Nest():
print(other_instance.level)
print(other_instance.level)
print(other_instance.level)
为什么需要嵌套类?只需让主要对象直接实现上下文管理协议:
class MyClass(object):
def __init__(self):
self.level = 0
def inclev(self):
self.level += 1
def declev(self):
self.level -= 1
__enter__ = inclev # For __enter__, just alias inclev, no need for wrapper
def __exit__(self, exc_type, exc_value, traceback):
self.declev()
然后只需将其用于:
with other_instance:
print(other_instance.level)
with other_instance:
print(other_instance.level)
print(other_instance.level)
如果您确实需要将上下文管理器协议作为一个名为Nest
的构造对象,您仍然可以使用contextlib
中的内置内容简化一点:
from contextlib import contextmanager
class MyClass(object):
def __init__(self):
self.level = 0
def inclev(self):
self.level += 1
def declev(self):
self.level -= 1
@contextmanager
def Nest(self):
self.inclev()
try:
yield
finally:
self.declev()
如果您使用标准命名约定,它确实可以帮助人们阅读您的代码。它还可以使语法突出显示工作。看看pep8,我已经编辑了你的代码(非功能性的)。你能检查一下我没有改变任何与这个问题相关的事情吗?@Holloway对此表示抱歉。是的,更改是可以的。我可能需要在类中使用不同的上下文管理器。我仍然可以用一种方式(通过传递参数)实现多个名称,但我更希望不同名称的简单性(从使用角度来看)。无论如何,我会考虑这个问题。杰勒比:我刚刚完成了“与问题相同的用法模式,但简化代码”的例子(我先发布了“最好”的方法,然后编辑添加另一个方法)。这将涵盖您想要的用例。谢谢,我更喜欢第二种方式。虽然可能有一种情况会让这看起来很自然,但现在它很可怕。为了不惹恼一年后必须阅读此代码的人(特别是如果是你自己!),让对象本身实现嵌套行为而没有任何指示器是令人毛骨悚然的。@AustinHastings:也许吧。取决于对象是否主要与标高跟踪有关
threading.RLock
基本上是相同的设计,它在不是所有者时锁定,并递增/递减计数,直到达到0,然后解锁,您只需将其与myrlock:一起使用即可。在一个类中混合许多不同的行为是令人困惑的;这实际上与使用(或不使用)上下文管理器无关。