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

前端 未结 6 1079
太阳男子
太阳男子 2021-01-02 02:15

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

6条回答
  •  温柔的废话
    2021-01-02 02:47

    Here is a decorator that automates making sure methods aren't called outside of a context manager:

    from functools import wraps
    
    BLACKLIST = dir(object) + ['__enter__']
    
    def context_manager_only(cls):
        original_init = cls.__init__
        def init(self, *args, **kwargs):
            original_init(self, *args, **kwargs)
            self._entered = False
        cls.__init__ = init
        original_enter = cls.__enter__
        def enter(self):
            self._entered = True
            return original_enter(self)
        cls.__enter__ = enter
    
        attrs = {name: getattr(cls, name) for name in dir(cls) if name not in BLACKLIST}
        methods = {name: method for name, method in attrs.items() if callable(method)}
    
        for name, method in methods.items():
            def make_wrapper(method=method):
                @wraps(method)
                def wrapper_method(self, *args, **kwargs):
                    if not self._entered:
                        raise Exception("Didn't get call to __enter__")
                    return method(self, *args, **kwargs)
                return wrapper_method
            setattr(cls, name, make_wrapper())
    
        return cls
    

    And here is an example of it in use:

    @context_manager_only
    class Foo(object):
        def func1(self):
            print "func1"
    
        def func2(self):
            print "func2"
    
        def __enter__(self):
            print "enter"
            return self
    
        def __exit__(self, *args):
            print "exit"
    
    try:
        print "trying func1:"
        Foo().func1()
    except Exception as e:
        print e
    
    print "trying enter:"
    with Foo() as foo:
        print "trying func1:"
        foo.func1()
        print "trying func2:"
        foo.func2()
        print "trying exit:"
    

    This was written as an answer to this duplicate question.

提交回复
热议问题