Search code examples
pythoncontextmanager

How should I handle None's in context managers in python?


In Python, the following pattern is quite common.

thing = x and load_thing(x)

which propagates None through your code (if x is None then so is thing). This is useful because later in your code you can check if thing is None and have different logic.

I'm not sure how to man this play well with context managers: the following code does not work (because if x is None, with None as y is not valid (because None does not have __enter__)

with x and load_thing(x) as y:
    f(y)

The best thing I've come up with is this, but I think the people reading my code might curse me (no sense of fun I tell you, no sense of fun).

@contextlib.contextmanager
def const_manager(x):
    yield x


with (const_manager(x) if x is None else load_thing(x)) as y:
    f(y)

Is there a more pythonic alternative? Besides layers and layers of function definitions and calls.


Solution

  • Put the test in your wrapper context manager.

    @contextlib.contextmanager
    def default_manager(cm, x):
        if x is None
            yield x
        else:
            yield cm(x)
    
    
    with default_manager(load_thing, x) as y:
        f(y)
    

    You might also consider using contextlib.nullcontext instead.

    with (load_thing if x is not None else nullcontext)(x) as y:
        f(y)