Skipping execution of -with- block

前端 未结 7 1964
Happy的楠姐
Happy的楠姐 2020-12-02 17:22

I am defining a context manager class and I would like to be able to skip the block of code without raising an exception if certain conditions are met during instantiation.

7条回答
  •  独厮守ぢ
    2020-12-02 17:51

    A python 3 update to the hack mentioned by other answers from withhacks (specifically from AnonymousBlocksInPython):

    class SkipWithBlock(Exception):
        pass
    
    
    class SkipContextManager:
        def __init__(self, skip):
            self.skip = skip
    
        def __enter__(self):
            if self.skip:
                sys.settrace(lambda *args, **keys: None)
                frame = sys._getframe(1)
                frame.f_trace = self.trace
    
        def trace(self, frame, event, arg):
            raise SkipWithBlock()
    
        def __exit__(self, type, value, traceback):
            if type is None:
                return  # No exception
            if issubclass(type, SkipWithBlock):
                return True  # Suppress special SkipWithBlock exception
    
    
    with SkipContextManager(skip=True):    
        print('In the with block')  # Won't be called
    print('Out of the with block')
    

    As mentioned before by joe, this is a hack that should be avoided:

    The method trace() is called when a new local scope is entered, i.e. right when the code in your with block begins. When an exception is raised here it gets caught by exit(). That's how this hack works. I should add that this is very much a hack and should not be relied upon. The magical sys.settrace() is not actually a part of the language definition, it just happens to be in CPython. Also, debuggers rely on sys.settrace() to do their job, so using it yourself interferes with that. There are many reasons why you shouldn't use this code. Just FYI.

提交回复
热议问题