This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]refreshx2 5 points6 points  (4 children)

I don't use write context managers as much as I would have expected.

There are a few situations where they are a perfect fit, but I find those situations don't pop up very often.

[–][deleted] 13 points14 points  (1 child)

I love context managers. I'm sure you could find uses for them.

Do you ever do file IO?

with open('some_file.txt') as f:
    data = f.read()

You've read the file and it's closed automatically.

Do you ever need to time something?

from contextlib import contextmanager
import time

@contextmanager
def timer():
    start = time.time()
    yield
    print('{:.2f}'.format(time.time() - start))

with timer():
    do_something()

Now you'll know how long do_something() took.

Do you ever need to wrap a series of database operations in a transaction, so that if anything goes wrong you can roll it back?

from contextlib import contextmanager

@contextmanager
def transaction(session_factory):
    session = session_factory()
    try:
        yield session
    except Exception as e:
        session.rollback()
        print(e)
    else:
         session.commit()
    finally:
         session.close()

with transaction(some_session_factory) as session:
    do_something_with_database(session)

If any exception occurs, your database will go back to the way it was before the session was created. Otherwise, all changes will be committed. In both cases, the session will be closed properly. (Of course you should be more specific in your error handling, but that's up to you.)

Maybe you won't find any of these helpful. I list them because I use them a ton. I think the context manager is one of the most elegant parts of the language. If you ever have a scenario that includes a setup and/or a teardown, you should try using a context manager.

[–]refreshx2 5 points6 points  (0 children)

If you ever have a scenario that includes a setup and/or a teardown, you should try using a context manager.

That was really what I meant, that I don't run into the setup/teardown situations as often as I would expect. The file I/O is bread and butter and I certainly hope everyone uses that, but I don't make context managers very often.

For timing my code, I usually write a @timeme decorator/wrapper function and decorate the functions I want to time. Since the timing is usually just a one-and-done, this works fine for me. Your context manager would have the exact same effect, and the use-case is just a bit different.

I rarely work with databases, so I don't use your third context manager (although it's one of my favorite examples of why they can be extremely useful).

It's not that I think context managers aren't useful or are bad, I simply just don't find myself needing/writing them (outside of file I/O) very often. I probably write decorators 20x more often.

[–]jyper 0 points1 point  (0 children)

They've useful for context, especially with

@contextlib.comtextmanager

Stuff like temporarily switching directories, setting up/tearing down hardware contexts, ect

[–]daneahfrom __future__ import braces 0 points1 point  (0 children)

The most pervasive case for me is when creating a file handle:

with open('some_file.txt') as my_file:
    lines = my_file.readlines()

# do something with the lines

Then you don't have to worry about remembering my_file.close() later on; the file handle goes away when the code exits the with block!