Home > Software design >  Is it bad practice to return function from inside with statement
Is it bad practice to return function from inside with statement

Time:01-27

Which one of the two examples below is the best practice?

@classmethod
def find(cls, *args, **kwargs):
    """Perform a find query in the DB."""
    with cls.connect() as conn:
        coll = conn[cls.DB][cls.COLLECTION]
        res = coll.find(*args, **kwargs)
        out = list(res)
        return out
@classmethod
def find(cls, *args, **kwargs):
    """Perform a find query in the DB."""
    with cls.connect() as conn:
        coll = conn[cls.DB][cls.COLLECTION]
        res = coll.find(*args, **kwargs)
        out = list(res)
    return out

I imagine this should essentially be interchangeable, since the context manager __exit__ method should be called anyways once the function returns, but I am not entirely sure.

CodePudding user response:

If the context manager is designed to swallow exceptions, your out will be undefined after with exits:

class Test:
    def __enter__(self):
        return 1

    def __exit__(self, exc_type, exc_val, exc_tb):
        return True


def x():
    with Test():
        some_error
        out = 1
        return out


def y():
    with Test():
        some_error
        out = 1
    return out


print(x())  # None
print(y())  # local variable 'out' referenced before assignment

Therefore, it makes more sense to keep return within the block.

CodePudding user response:

The context manager's exit might affect the result, so that it matters whether you return before or after that exit (i.e., inside or outside the with block). For example a function that writes a file and returns the file size:

from os.path import getsize

def foo():
    with open('foo', 'w') as f:
        f.write('foo')
        return getsize('foo')

def bar():
    with open('bar', 'w') as f:
        f.write('bar')
    return getsize('bar')

print(foo(), bar())

Output (Try it online!):

0 3

When I return inside, the file hasn't been flushed/closed yet. That's wrong.

So at least in such cases, you should return outside.

(For documentation about how a return inside a with block is handled, see the "semantically equivalent" code here. The with block is executed in a try, and the manager's exit is done in its finally.)

  • Related