[Python-Dev] Multiline with statement line continuation (original) (raw)
Ian Cordasco graffatcolmingov at gmail.com
Tue Aug 12 15:04:35 CEST 2014
- Previous message: [Python-Dev] Multiline with statement line continuation
- Next message: [Python-Dev] Multiline with statement line continuation
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Tue, Aug 12, 2014 at 7:15 AM, Steven D'Aprano <steve at pearwood.info> wrote:
On Tue, Aug 12, 2014 at 10:28:14AM +1000, Nick Coghlan wrote:
On 12 Aug 2014 09:09, "Allen Li" <cyberdupo56 at gmail.com> wrote: > > This is a problem I sometimes run into when working with a lot of files > simultaneously, where I need three or more
with
statements: > > with open('foo') as foo: > with open('bar') as bar: > with open('baz') as baz: > pass > > Thankfully, support for multiple items was added in 3.1: > > with open('foo') as foo, open('bar') as bar, open('baz') as baz: > pass > > However, this begs the need for a multiline form, especially when > working with three or more items: > _> with open('foo') as foo, _ _> open('bar') as bar, _ _> open('baz') as baz, _ _> open('spam') as spam _ > open('eggs') as eggs: > passI generally see this kind of construct as a sign that refactoring is needed. For example, contextlib.ExitStack offers a number of ways to manage multiple context managers dynamically rather than statically. I don't think that ExitStack is the right solution for when you have a small number of context managers known at edit-time. The extra effort of writing your code, and reading it, in a dynamic manner is not justified. Compare the natural way of writing this: with open("spam") as spam, open("eggs", "w") as eggs, frobulate("cheese") as cheese: # do stuff with spam, eggs, cheese versus the dynamic way: with ExitStack() as stack: spam, eggs = [stack.entercontext(open(fname), mode) for fname, mode in zip(("spam", "eggs"), ("r", "w")] cheese = stack.entercontext(frobulate("cheese")) # do stuff with spam, eggs, cheese I prefer the first, even with the long line.
I agree with Steven for small numbers of context managers. Once they become too long though, either refactoring is severely needed or the user should ExitStack.
To quote Ben Hoyt:
Is it meaningful to use "with" with a tuple, though? Because a tuple isn't a context manager with enter and exit methods. For example:
>>> with (1,2,3): pass ... Traceback (most recent call last): File "", line 1, in AttributeError: exit So -- although I'm not arguing for it here -- you'd be turning an code (a runtime AttributeError) into valid syntax.
I think by introducing parentheses we are going to risk seriously confusing users who may then try to write an assignment like
a = (open('spam') as spam, open('eggs') as eggs)
Because it looks like a tuple but isn't and I think the extra complexity this would add to the language would not be worth the benefit. If we simply look at Ruby for what happens when you have an overloaded syntax that means two different things, you can see why I'm against modifying this syntax. In Ruby, parentheses for method calls are optional and curly braces (i.e, {}) are used for blocks and hash literals. With a method on class that takes a parameter and a block, you get some confusing errors, take for example:
class Spam def eggs(ham) puts ham yield if block_present? end end
s = Spam.new s.eggs {monty: 'python'} SyntaxError: ...
But
s.eggs({monty: 'python'})
Will print out the hash. The interpreter isn't intelligent enough to know if you're attempting to pass a hash as a parameter or a block to be executed. This may seem like a stretch to apply to Python, but the concept of muddling the meaning of something already very well defined seems like a bad idea.
- Previous message: [Python-Dev] Multiline with statement line continuation
- Next message: [Python-Dev] Multiline with statement line continuation
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]