Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set your subtitle preferences in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please see our video player troubleshooting guide to resolve the issue.

Function-Based Context Managers With "contextlib"

In the last two lessons you worked with a class-based context manager. In this video you’ll learn how to implement a function-based context manager using Python’s contextlib module.

00:00 Now, I just explained to you how class-based context managers work, but this isn’t the only way to support the with statement in Python, and this is not the only way to implement a context manager.

00:13 So, there is the contextlib module in the standard library, and it provides a couple of abstractions on top of the basic context manager protocol.

00:23 And this can make your life a little easier if you’re trying to implement a use case that matches well with what the contextlib module offers.

00:32 So, here’s a quick example of what you can do with this. I’m going to re-implement the same ManagedFile functionality using the contextlib library. So, there’s a decorator in there called contextmanager and this thing is highly useful.

00:47 What that allows you to do is you can define objects that follow the context manager protocol that you can use with the with statement simply by writing a generator.

00:59 So, when looking at this code, again, you can see our familiar try and finally pattern here, where I’m acquiring the resource and then I’m yielding it, and then later, I’m closing the resource.

01:12 And what happens is that this @contextmanager decorator will turn this generator function—or, this generator that I just defined here—it will turn that into a full-blown context manager that I can use with the with statement. So again, I can do something like this.

01:32 I can say with managed_file('hello.txt')

01:40 I’m just going to call it f again. I can say, “Write something to the file,” and of course we can also write more stuff to the same file. And now, when I run this, we’re actually writing to the file.

01:52 If you’re wondering what this is—so, this is just the number of characters written, because .write() returns how many characters were written to the file, right?

01:59 It’s just kind of leaking back into my interpreter session here.

Gilles Consulting on May 9, 2019

Hello, Thanks for you videos. very clear, even if for this one I have 2 questions:

I am wondering why you defined a generator, with a yield, instead of a return. well, it does not work with a return :) I can’t get why a generator is needed.. Could you clarify that please?

Also, if I understand properly, in you managed_file function the “try:” is taken in charge by the __enter__ function, and the finally by the __exit__ one (cf the class you defined in your previous video to reproduce the with behavior. Could you confirm if it’s correct?

Thank you in advance.

Dan Bader RP Team on May 9, 2019

I can’t get why a generator is needed.. Could you clarify that please?

Ah, the reason is that contextlib.contextmanager requires a generator :) Using a generator allows the function to be temporarily “paused” and then later resumed again for the context manager’s “exit” step. A regular function can’t do that sort of thing, hence the yield to define a generator.

Become a Member to join the conversation.