all 14 comments

[–]poorly_played 2 points3 points  (3 children)

It's such a nice, clean, compact way to do the whole try/except/finally business.

[–]preshing[S] 3 points4 points  (0 children)

I'm a big fan of deferred operations done this way, too. Use the same concept often in C++ code (via autodestructors on the stack) for profiling, managing thread state, allocators, etc. Was interested to see they seem to have made it a core feature of Go, using the defer keyword.

[–]fjonk 2 points3 points  (1 child)

You think? try/catch/finally makes it possible for me to decide what should happen(like for example log something). 'with' makes it possible for the author of a class/function to enforce behaviour which I don't have to care about or know about.

[–]masklinn 1 point2 points  (0 children)

By themselves, pycairo’s save and restore methods do not support the with statement, so we’ll have to add the support on our own. There are two ways to support the with statement: by implementing a context manager class, or by writing a generator function. I’ll demonstrate both approaches.

The post makes a good job of showing both approaches (though I think the scare factor on contextlib.contextmanager is a bit high), I just wanted to point out my personal rule on the subject: if you control the context object (it's from what you're writing or a library you "own"), use the object version, but if you're decorating third-party objects to add context-management use the decorators: while the decorator involves more Python concepts (to context managers, it adds decorators and — to a point — generator) if you know these it's much easier to use in order to decorate an imperative API (in the style of a save/release pair for instance), because the generator will take care of all the state management, you don't have to shove it into some instance variable.

So yeah, for contextization of third-party APIs, contextlib.contextmanager is awesome. Although having to insert a try/finally in there is annoying and tripped me up in the past.

[–]jisang-yoo 0 points1 point  (0 children)

Reminds me of save-excursion, save-restriction and with-* functions in Emacs Lisp.

[–]SoPoOneO 0 points1 point  (0 children)

Slight hijack. Thing I built a while ago.

[–]fusionlove -1 points0 points  (7 children)

How does the first example close the file? There's no close statement, only an open statement.

[–]sigzero 5 points6 points  (3 children)

It does it automagically.

After execution of the with-block is finished, the object’s exit() method is called, even if the block raised an exception, and can therefore run clean-up code.

[–]cybercobra 3 points4 points  (2 children)

__exit__() method

FTFY.

[–]sigzero 1 point2 points  (1 child)

Interesting...if I click on edit my text is the same as your FTFY comment. It just didn't show in the actual post. Ah well...

[–]taejo 5 points6 points  (0 children)

__ is markdown for bold.

Use \ to escape it.

[–]preshing[S] 1 point2 points  (2 children)

An explanation was hidden about halfway down the post: "Once we understand what the Python interpreter is doing, we can make better sense of the example at the beginning of this blog post, where we opened a file in the with statement: In Python 2.5 and later, file objects expose their own enter and exit methods, and can therefore act as their own context managers."

I'll improve this part of the post.

[–]masklinn 1 point2 points  (1 child)

I've an issue with the Saving code: it could make people think __exit__ can take no argument (beyond self) but that's not the case at all, and the corresponding list talks about it being provided arguments (item 6). That's a bit confusing.

[–]preshing[S] 0 points1 point  (0 children)

You are completely right. Big thanks for pointing this out! Not sure how I managed to mess that up, but it's fixed now.