Hacker News new | past | comments | ask | show | jobs | submit login

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



I think I prefer this version:

    class Session:
        def __init__(self):
            self._connection = db.connect(...)

        def __enter__(self):
            self._connection.__enter__(self)
            return self

        def __exit__(self, *args):
            return self._connection.__exit__(self)

        def login(self, name, password):
            self._connection.query(...)

    with Session() as session:
        ...
It might need a bit more knowledge about context managers [1], but it feels less magic and more explicit to me – i.e. more pythonic :). But it also contains the assumption that db.connection already returns the connection. If that is not true, a bit more housekeeping is needed:

    class Session:
        def __init__(self):
            self._connection_context = db.connect(...)

        def __enter__(self):
            self._connection = self._connection_context.__enter__(self)
            return self

        def __exit__(self, *args):
            return self._connection_context.__exit__(self)

        def login(self, name, password):
            self._connection.query(...)

[1] https://docs.python.org/3/library/stdtypes.html#typecontextm...


it's subjective of course, but I find context manager decorators very pythonic, I still remember the 'whoa! that's beautiful' moment when I 1st learned about them.

But most importantly, generators as enclosures are used everywhere today with the whole async-await paradigm.


I absolutely agree – it's the specific usage in the class that I don't like. Having a factory instead of using the constructor, with that IMHO not that obvious interaction with the context manage. A factory that is actually a context manager just seems non-trivial, and given that there is more straightforward solution available, I would avoid it.


This is just what I needed. Thank you!




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: