Reputation: 850
Below is a hypothetical piece of code
with dbengine.connect(**details) as db:
cur = db.exec(sql_string)
results = cur.fetchall()
return results
In this case I would expect that when tabbed out of that with block db.close() is called and db is marked for garbage collection.
In work I've started seeing this code crop up.
with something() as myobj:
logger.info('I got an obj!')
return myobj
I don't know if you should be using with like the new keyword in java. Could someone direct me to any good docs that might explain what you can/can't should/shouldn't do when using with?
P.S Log messages are actually that lame :-)
Upvotes: 1
Views: 355
Reputation: 1125398
The target name the with
statement binds the contextmanager __enter__
return value to (the name after as
) is not scoped to just the with
statement. Like for
loop variable, the as
target name is scoped in the current function or module namespace. The name does not disappear or is otherwise cleared when the with
suite ends.
As such, return myobj
outside of the with
statement is perfectly legal, if somewhat nonsensical. All that the with
statement guarantees is that the something().__exit__()
method will have been called when the block completes (be that by reaching the end of the block, or because of a continue
, break
or return
statement, or because an exception has been raised).
That said, you'd be better off just moving the return inside the with
statement:
with something() as myobj:
logger.info('I got an obj!')
return myobj
and
with dbengine.connect(**details) as db:
cur = db.exec(sql_string)
return cur.fetchall()
The context manager will still be cleaned up properly, but now the return
statement looks like it is a logical part of the with
block. The execution order is not altered; something().__exit__()
is called, then the function returns.
As always, the Python documentation on the with
syntax is excellent. You could also review the documentation on context managers and the original proposal, PEP-343.
Upvotes: 2