Search code examples
pythonpython-3.xdecoratorpython-decorators

How to short-circuit a function using Python decorators?


Say I have a function F that may return boolean false. If I have a caller named main() that will call F in multiple places, can I attach a decorator to F that will propagate the return value and cause its parent (main) to also exit early?


Solution

  • No function can 'return' to a context higher than it's caller. This (to my knowledge) is universal in most programming languages. You could probably hack it by inspecting the python state and call stack, but a much better / more appropriate solution would be to wrap main in a try: except: block that catches a custom exception that you raise inside this decorator depending on the output of F()

    import random
    from functools import wraps
    
    class ShortCircuit(Exception):
        pass
    
    def short_circuit(f):
        @wraps(f)
        def wrapped(*args, **kwargs):
            res = f(*args, **kwargs)
            if not res:
                raise ShortCircuit()
            else:
                return res
        return wrapped
    
    @short_circuit
    def F():
        return random.choice([True, False])
    
    def main():
        print(F())
        print(F())
    
    if __name__=="__main__":
        try:
            main()
        except ShortCircuit:
            print("short circuited")