编写一个只能用作上下文管理器的 Python class
Writing a Python class that can only be used as a context manager
在 Python 中有没有一种方法可以编写一个 class 除非与 with 语句一起使用否则会出错?
# Okay:
with Foo() as f1:
f1.func1()
f1.func2()
# Not okay:
f2 = Foo()
f2.func1()
我可以手动完成:让 __enter__
设置一个标志并让所有其他方法检查该标志。但是有更好的方法吗?
这是不那么自在的方式的代码:
class Foo(object):
def __init__(self):
self._entered = False
def __enter__(self):
self._entered = True
return self
def _verify_entered(self):
if not self._entered:
raise Exception("Didn't get call to __enter__")
def __exit__(self, typ, val, traceback):
self._verify_entered()
print("In __exit__")
def func1(self):
self._verify_entered()
# do stuff ...
def func2(self):
self._verify_entered()
# do other stuff
如果您不希望用户能够调用上下文管理器对象本身的方法,您可以将 __enter__
方法 return 设置为与 self
不同的对象。
class Foo(object):
def __enter__(self):
print("In __enter__")
return Bar()
def __exit__(self, typ, val, traceback):
print("In __exit__")
class Bar(object):
def func1(self):
print("In func1")
def func2(self):
print("In func2")
你当然可以将 Foo
和 Bar
class 联系在一起,而不是我在这个例子中所做的。例如,Foo
class 可以将自身传递给 __enter__
.
中的 Bar
构造函数
调用 Foo().func1()
将不起作用,原因很明显 Foo
没有任何此类方法。如果您希望 Bar
对用户不可见,您可以在其名称前加上下划线(暗示它是内部的)或者甚至将其嵌套在 Foo
class(甚至__enter__
方法,如果你真的想走极端的话)。
从技术上讲,我认为 agf 在您可以使用元class 来自动化这些东西的意义上是正确的。但是,如果我正确理解其背后的基本动机,我会提出不同的建议。
假设您有一个 Payload
class 要通过上下文管理器保护。在这种情况下,您只需创建一个 returns 的上下文管理器:
# This should go in a private module.
class Payload(object):
def __init__(self):
print 'payload ctor'
# This should go in the public interface.
class Context(object):
def __init__(self):
# Set up here the parameters.
pass
def __enter__(self):
# Build & return a Payload object
return Payload()
def __exit__(self, exc_type, exc_val, exc_tb):
# Cleanup
pass
with Context() as f:
# f here is a Payload object.
如果你将 Payload
隐藏在私有模块中,你就很好。
在 Python 中有没有一种方法可以编写一个 class 除非与 with 语句一起使用否则会出错?
# Okay:
with Foo() as f1:
f1.func1()
f1.func2()
# Not okay:
f2 = Foo()
f2.func1()
我可以手动完成:让 __enter__
设置一个标志并让所有其他方法检查该标志。但是有更好的方法吗?
这是不那么自在的方式的代码:
class Foo(object):
def __init__(self):
self._entered = False
def __enter__(self):
self._entered = True
return self
def _verify_entered(self):
if not self._entered:
raise Exception("Didn't get call to __enter__")
def __exit__(self, typ, val, traceback):
self._verify_entered()
print("In __exit__")
def func1(self):
self._verify_entered()
# do stuff ...
def func2(self):
self._verify_entered()
# do other stuff
如果您不希望用户能够调用上下文管理器对象本身的方法,您可以将 __enter__
方法 return 设置为与 self
不同的对象。
class Foo(object):
def __enter__(self):
print("In __enter__")
return Bar()
def __exit__(self, typ, val, traceback):
print("In __exit__")
class Bar(object):
def func1(self):
print("In func1")
def func2(self):
print("In func2")
你当然可以将 Foo
和 Bar
class 联系在一起,而不是我在这个例子中所做的。例如,Foo
class 可以将自身传递给 __enter__
.
Bar
构造函数
调用 Foo().func1()
将不起作用,原因很明显 Foo
没有任何此类方法。如果您希望 Bar
对用户不可见,您可以在其名称前加上下划线(暗示它是内部的)或者甚至将其嵌套在 Foo
class(甚至__enter__
方法,如果你真的想走极端的话)。
从技术上讲,我认为 agf 在您可以使用元class 来自动化这些东西的意义上是正确的。但是,如果我正确理解其背后的基本动机,我会提出不同的建议。
假设您有一个 Payload
class 要通过上下文管理器保护。在这种情况下,您只需创建一个 returns 的上下文管理器:
# This should go in a private module.
class Payload(object):
def __init__(self):
print 'payload ctor'
# This should go in the public interface.
class Context(object):
def __init__(self):
# Set up here the parameters.
pass
def __enter__(self):
# Build & return a Payload object
return Payload()
def __exit__(self, exc_type, exc_val, exc_tb):
# Cleanup
pass
with Context() as f:
# f here is a Payload object.
如果你将 Payload
隐藏在私有模块中,你就很好。