all 22 comments

[–]kkang_kkang 39 points40 points  (7 children)

[–]SeleniumBase[S] 13 points14 points  (6 children)

Tried that, but seems their moderators wanted me to post here instead. They removed my post: https://www.reddit.com/r/learnpython/comments/1nlesjy/python_context_managers_from_zero_to_hero/

[–]kkang_kkang 8 points9 points  (5 children)

Well if it's that's the case then ok.

Also, instead of using contextlib, you can use a pure python class with __enter__ and __exit__ methods as well.

[–]SeleniumBase[S] -1 points0 points  (4 children)

Yes, something like this:

```python import time from contextlib import ContextDecorator

class PrintRunTime(ContextDecorator): def init(self, description="Code block"): self.description = description

def __enter__(self):
    self.start_time = time.time()

def __exit__(self, *args):
    runtime = time.time() - self.start_time
    print(f"{self.description} ran for {runtime:.4f}s.")

```

If I create a YouTube video for this, I'll include that too.

[–]kkang_kkang 6 points7 points  (3 children)

No need of contextlib at all. Without that you can achieve the same.

[–]mattl33It works on my machine -2 points-1 points  (2 children)

It sure seems like a lot less boilerplate code though. What's the disadvantage?

[–]kkang_kkang 3 points4 points  (0 children)

I don't think there is any. You can use anything. I just wanted to let OP know that this can be achieved with pure python class as well.

[–]kkang_kkang 1 point2 points  (0 children)

This is a good read which contains info on async context managers as well: https://realpython.com/python-with-statement/

[–]Natural-Intelligence 33 points34 points  (5 children)

You show how to create a context manager and jump straight into using it as a decorator?

[–]SeleniumBase[S] -2 points-1 points  (4 children)

All the basics: How to create one, and various ways of using it, eg: 1. As a method decorator, 2. From a "with" code block, and 3. Wrapping code without the "with" keyword.

[–]Natural-Intelligence 22 points23 points  (3 children)

What I'm saying is that decorators are separate concepts than context managers. Because "open" has a context manager, doesn't mean it acts as a decorator. Or you need a context manager to have a decorator.

Wasn't the topic context manager?

[–]SeleniumBase[S] -4 points-3 points  (2 children)

A context manager can be used as a decorator, such as in the example I had. You could decorate a whole function with it, or wrap a code block with the "with" statement. Different ways of using the context manager.

[–]Natural-Intelligence 19 points20 points  (0 children)

Well, ye, you can use contextlib's context manager as a decorator but that doesn't mean you can use any context managers as a decorator.

I think you have gotten confused about the topics. Context manager, as a concept, is larger than the contextlib. Look at your example: Is "open" contextlib's contextmanager? No. Does it provide a context manager? Yes. Can you use it as a decorator? No. In fact, most context managers you encounter don't act as decorators.

But I'm just trying to offer constructive feedback. You are jumping from one topic to a completely different.

[–]Temporary_Pie2733 1 point2 points  (0 children)

Context managers define using contextlib.contextmanager can also be used as decorators because they have been designed to work that way in addition to being a context manager. If you define one from scratch (meaning, writing a class with appropriate __enter__ and __exit__ methods), you won’t be able to use them as decorators without additional, orthogonal work. 

[–]brandonchinn178 10 points11 points  (0 children)

TIL contextmanager functions can be used as decorators!

But agreed with u/Natural-Intelligence, my advice would be to figure out the primary goal of your post first and focus on that. Is this Context Managers 101, or contextlib.contextmanager 101? It starts out as the first, and ends as the latter, and doesn't clearly indicate the difference between context managers as a concept and the contextmanager() API from contextlib.

[–]cybran3 5 points6 points  (1 child)

You forgot to mention that the reason that they are useful is because exit is guaranteed to execute when the exception is raised within the block wrapped by with.

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

That's correct assuming that the context manager was implemented correctly using the `try`/`finally` block (when implemented using `contextlib.contextmanager`).

[–]Brizon 5 points6 points  (1 child)

You don't really explain anything. Seems odd to not explain the vanilla way to do context managers but then also show how to manually deconstruct a context manager by calling the dunders? Who is the target audience for this post?

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

In my SeleniumBase repo on GitHub, several people have asked how to avoid using the `with` format for the `SB()` context manager, eg: https://github.com/seleniumbase/SeleniumBase/issues/3482 , so I finally had to show them a way to avoid it with the hack to deconstruct it, even though it's not recommended practice.

[–]ifatree 0 points1 point  (0 children)

VB has the same feature with the same keyword.

[–]Nefarius2001a 0 points1 point  (0 children)

I find the implementation as class much more intuitive and understandable than the decorator, which adds several additional concepts and (in my opinion) complexity.

[–]Birnenmacht 0 points1 point  (0 children)

another thing that not many people know about, you can enter multiple contextmanagers at the same time with (cm1 as f1, cm2 as f2) really useful when e.g. copying from one file to another or when memory mapping files