Parenthesized context managers

Viewed 875

I'm trying to understand what is new with the new parenthesized context managers feature in Python 3.10 (top item in new features here).

My test example was to try and write:

with (open('file1.txt', 'r') as fin, open('file2.txt', 'w') as fout):
    fout.write(fin.read())

A super simple test, and it works perfectly in Python 3.10.

My problem is that it also works perfectly in Python 3.9.4?

Testing this in Python 3.8.5, it looks like it doesn't work, raising the expected SyntaxError.

Am I misunderstanding this update as it seems this new syntax was introduced in 3.9?

1 Answers

I didn't know this was in, but I'm glad to see it. Professionally I've used 3.6 (which doesn't have this), and with multiple long line context managers and black, it's really hard to format:

If you have this:

with some_really_long_context_manager(), and_something_else_makes_the_line_too_long():
    pass

You have to write this which is ugly:

with some_really_long_context_manager(), \
    and_something_else_makes_the_line_too_long():
    pass

If your arguments are too long:

with some_context(and_long_arguments), and_another(now_the_line_is_too_long):
    pass

You can do something like:

with some_context(and_long_arguments), and_another(
    now_the_line_is_too_long
):
    pass

But that doesn't work if one context manager doesn't take arguments, and it looks slightly odd anyway:

with some_context(and_long_arguments), one_without_arguments(
    ), and_another(now_the_line_is_too_long):
    pass

To do this, you have to rearrange:

with some_context(and_long_arguments), and_another(
    now_the_line_is_too_long
), one_without_arguments():
    pass

With the new syntax, this can be formatted as:

with (
    some_context(and_long_arguments),
    one_without_arguments(), 
    and_another(now_the_line_is_too_long), 
):
    pass

This also makes diffs more readable.

Related