I dislike the argument about context managers being unusable if you have a class that needs to re-use some context across many methods.
There are a lot of ways to do so comfortably. A trick I really like is to use `contextlib.contextmanager`, and have a pure constructor and a separate static factory method that injects appropriate contexts. This also makes the code more loosely coupled in general :-)
from contextlib import contextmanager
class Session:
@classmethod
@contextmanager
def create(cls):
with db.connect(...) as connection:
yield cls(connection)
def __init__(self, connection: db.Connection):
self._connection = connection
def login(self, name, password):
self._connection.query(...)
with Session.create() as session:
...