Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
230 views
in Technique[技术] by (71.8m points)

python - How to check if an object is created with `with` statement?

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:
 ...

and this is not:

x = X()

How can I ensure such functionality?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There is no straight forward way, as far as I know. But, you can have a boolean flag, to check if __enter__ was invoked, before the actual methods in the objects were called.

class MyContextManager(object):

    def __init__(self):
        self.__is_context_manager = False

    def __enter__(self):
        print "Entered"
        self.__is_context_manager = True
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print "Exited"

    def do_something(self):
        if not self.__is_context_manager:
            raise Exception("MyContextManager should be used only with `with`")

        print "I don't know what I am doing"

When you use it with with,

with MyContextManager() as y:
    y.do_something()

you will get

Entered
I don't know what I am doing
Exited

But, when you manually create an object, and invoke do_something,

x = MyContextManager()
x.do_something()

you will get

Traceback (most recent call last):
  File "/home/thefourtheye/Desktop/Test.py", line 22, in <module>
    x.do_something()
  File "/home/thefourtheye/Desktop/Test.py", line 16, in do_something
    raise Exception("MyContextManager should be used only with `with`")
Exception: MyContextManager should be used only with `with`

Note: This is not a solid solution. Somebody can directly invoke __enter__ method alone, before calling any other methods and the __exit__ method may never be called in that case.

If you don't want to repeat that check in every function, you can make it a decorator, like this

class MyContextManager(object):

    def __init__(self):
        self.__is_context_manager = False

    def __enter__(self):
        print "Entered"
        self.__is_context_manager = True
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        print "Exited"

    def ensure_context_manager(func):
        def inner_function(self, *args, **kwargs):
            if not self.__is_context_manager:
                raise Exception("This object should be used only with `with`")

            return func(self, *args, **kwargs)
        return inner_function

    @ensure_context_manager
    def do_something(self):
        print "I don't know what I am doing"

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...