I would like to ensure that the class is only instantiated within a \"with\" statement.
i.e. this one is ok:
with X() as x:
...
an
OP's question was believed to be an XY problem, and the current chosen answer was indeed (too?) hacky.
I don't really know the OP's original "X problem", but I'd assume the motivation was NOT literally about to "prevent x = X() ASSIGNMENT from working". Instead, it could be about to force the API user to always use x as a context manager, so that its __exit__(...) would always be triggered, which is the whole point of designing class X to be a context manager in the first place. At least, that was the reason brought me to this Q&A post.
class Holder(object):
def __init__(self, **kwargs):
self._data = allocate(...) # Say, it allocates 1 GB of memory, or a long-lived connection, etc.
def do_something(self):
do_something_with(self._data)
def tear_down(self):
unallocate(self._data)
def __enter__(self):
return self
def __exit__(self, *args):
self.tear_down()
# This is desirable
with Holder(...) as holder:
holder.do_something()
# This might not free the resource immediately, if at all
def foo():
holder = Holder(...)
holder.do_something()
That said, after learning all the conversations here, I ended up just leave my Holder class as-is, well, I just added one more docstring for my tear_down():
def tear_down(self):
"""You are expect to call this eventually; or you can simply use this class as a context manager."""
...
After all, we are all consenting adults here...