OSDir


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

"Data blocks" syntax specification draft


On Wed, May 23, 2018 at 1:22 AM, Ian Kelly <ian.g.kelly at gmail.com> wrote:
> On Tue, May 22, 2018 at 8:25 AM, Chris Angelico <rosuav at gmail.com> wrote:
>> On Tue, May 22, 2018 at 8:25 PM, bartc <bc at freeuk.com> wrote:
>>> Note that Python tuples don't always need a start symbol:
>>>
>>>    a = 10,20,30
>>>
>>> assigns a tuple to a.
>>
>> The tuple has nothing to do with the parentheses, except for the
>> special case of the empty tuple. It's the comma.
>
> Although, if the rule were really as simple as "commas make tuples",
> then this would be a list containing a tuple: [1, 2, 3].

In an arbitrary expression, a comma between two expressions creates a
tuple. In other contexts, the comma has other meanings, which take
precedence:

* Separating a function's arguments (both at definition and call)
* Enumerating import targets and global/nonlocal names
* Separating an assertion from its message
* Listing multiple context managers
* And probably some that I've forgotten.

In those contexts, you can override the normal interpretation and
force the tuple by using parentheses, preventing it from being parsed
as something else, and making it instead a single expression:

print((1, 2)) # prints a tuple
print(1, 2) # prints two items

The comma is what makes the tuple, though, not the parentheses. The
parentheses merely prevent this from being something else.

> Curiously, parentheses are also sometimes required for iterable
> unpacking. For example:
>
> py> 1, 2, *range(3,5)
> (1, 2, 3, 4)
> py> d = {}
> py> d[1, 2] = 42
> py> d[1, 2, *range(3,5)] = 43
>   File "<stdin>", line 1
>     d[1, 2, *range(3,5)] = 43
>             ^
> SyntaxError: invalid syntax

I'm not sure what you mean about the parentheses here. AIUI iterable
unpacking simply isn't supported inside subscripting. If that's an
actual problem anywhere, I'm sure it could be added :)

> py> def foo():
> ...   return 1, 2
> ...
> py> foo()
> (1, 2)
>
> py> def foo():
> ...   return 1, 2, *range(3, 5)
>   File "<stdin>", line 2
>     return 1, 2, *range(3, 5)
>                  ^
> SyntaxError: invalid syntax

That's a slightly curious case, since it's definitely being parsed the
same way. PEP 448 gives precedence for adding this sort of thing, if
anyone feels like digging into it. You may find that there's some
ambiguity somewhere in the unparenthesized version.

> py> def foo():
> ...   yield 1, 2
> ...
> py> list(foo())
> [(1, 2)]
> py> def foo():
> ...   yield 1, 2, *range(3, 5)
>   File "<stdin>", line 2
>     yield 1, 2, *range(3, 5)
>                 ^
> SyntaxError: invalid syntax

That's the exact same thing as the 'return' example, so it'll behave
the same way.

> py> for x in 1, 2: print(x)
> ...
> 1
> 2
> py> for x in 1, 2, *range(3, 5): print(x)
>   File "<stdin>", line 1
>     for x in 1, 2, *range(3, 5): print(x)
>                    ^
> SyntaxError: invalid syntax

In fact, I think probably all four of your examples would behave the
same way. So if you want to push for the change, go for it :)

ChrisA