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
.)