Syntax error for naked trailing comma for 1-tuple

No need to be snarky

6 Likes

Excuse my ignorance, but how do we do that? And what does the difference mean?

You need to set up a CPython development environment with C level coverage measurement (I’m using Clang’s coverage tools). IIRC, the dev guide has a section about how to set up gcov[1]. I did not check what the difference meant; I only observed there was one[2].

Tests need a broad kind of input so one is sure the underlying code is correct for all possible code paths. A slight change in input might produce a completely different code path.


  1. Found it: Increase test coverage ↩︎

  2. I do not intend to find out what the difference is either. ↩︎

To take your objection charitably, I think I need to show this if my aim is to demonstrate that the trailing comma should raise a syntax warning. This would be true, as then I would have to demonstrate that no non-golfer uses this kind of code intentionally, and that it wouldn’t be too much of a hassle to make some previously working Python code raise a warning all of a sudden - sure, warnings are not backwards-incompatible code, but it is a form of suddenly introduced code smell. However, I think the discussion in this thread shows that the best recourse would be something like adding the trailing comma tuple rule into PEP8 style guide, at the very least to strongly incentivize linters to pick up on this probably undesired coding practice and make it easier to catch swiftly. As I agree that this would be a reasonable recourse, I don’t have a need to have a high evidence threshold, as there is no problem with backwards compatibility - very clever Python coders who intentionally declare 1-tuples with trailing commas can just ignore their PyCharm/VSCode/Spyder linter, so no code smell is suddenly introduced. And, as this thread shows, I think there is plenty of evidence in this thread that this would be a valuable addition to the PEP8 style guide - there are realistic scenarios where code refactoring done by Python coders of all experience levels leaves behind an unintentional trailing comma which is tough to debug swiftly even by experienced Django veterans, and these scenarios occur more often than brute syntax errors which Django pros crack like walnuts.

Question: Does the Python Standard Library benefit from this change? PEP 8 is not a style guide for all Python code, everywhere. It is a style guide for the Python Standard Library (the portions written in Python). The bar for changes which do not inpact the stdlib is quite a bit higher.

1 Like

Well, the standard library code has to be 1) coded; 2) reviewed; 3) debugged; 4) read many times. I would imagine that explicit 1-tuples would help with all these factors, most importantly with 3 and 4.

When I started learning Python, I was taught that the comma is not only a delimiter but also an operator that can produce a tuple. It was clear and straightforward. I don’t think beginners will be confused with the explanation.

So I understand that the comma in the import statement is a delimiter and it is reasonable to get the following syntax error:

>>> from sys import (path,)
>>> from sys import path,
  File "<input>", line 1
    from sys import path,
                         ^
SyntaxError: trailing comma not allowed without surrounding parentheses

But I think there’s a little room to have mercy on this.

It hurts my foot to hear people say that calling this a foot gun is a stretch, given that I shot myself in the foot with it 10 hours ago (just a stray comma at the end of a line, that I didn’t intend at all) and just now spent the past 10 hours debugging it.

I can’t claim that this happens often with this particular construct, but so what-- I’d very much prefer that it never happen to me again, given that the currently-legal syntax has no benefit whatsoever, as far as I can see.

I’d also prefer not to have to read other peoples’ code which has this construct, intentionally or not. The comma in this context is simply easy to miss when reading, for me and, I assert, for almost everyone else, so this construct tends to be a speed bump, at best, for people trying to read other peoples’ code, even if it’s indeed perfectly clear syntax to some small subset of people. Do you care if your code is readable to others? If not, I think your opinion probably shouldn’t carry much weight on the topic of what would be good for the python community.

3 Likes

I don’t know about raising an error, but I would definitely discourage it and make it so IDEs will warn about this

Ruff catches it: COM818

2 Likes

Did you not see the mentioned ones or do you disagree with them?

The argument for the status quo is that it’s the status quo, not that naked 1-tuples have a benefit… I think? I re-read/skimmed through the comments above and that’s what I got from it.

[I ran into “sorry, new users can mention at most 2 users in a post”, so I intentionally broke some of the at-sign references, sorry]

I wrote:

no benefit whatsoever, as far as I can see.

@pochmann replied:

Did you not see the mentioned ones or do you disagree with them?

Hi Stefan,

I certainly overstated the case when I said “no benefit whatsoever”, so thanks for calling me on that; I’m not a fan of sloppy language. Rephrasing that without hyperbole, I’d say, instead, that all the benefits of the syntax that people have mentioned seem relatively weak, compared to its significant drawbacks (low readability, bug-proneness).

Going back over this thread carefully, looking for what people described as benefits
(not including short-term porting and migration pain), I see the following; let me know if you think I missed any others. The biggest real benefit I saw cited being your pointing out that you can’t quickly comment-out tests = test1, #test2, test3, I address that in more detail below.

=========

Nov 22, @ vovavili wrote:

if you’re in an interactive Python session or feel like code golfing: […] Which saves you one keystroke over: […]

This is funny, but I don’t read it as being a serious reason.

=========

Nov 22, @ pochmann wrote:

Parentheses for the 1-tuple would reduce consistency with the other lines:
foos = 1, 2
bars = 3,
quxs = 4, 5, 6

I guess I’d say it’s already inconsistent (none of the other lines have a trailing comma); and I guess this would make it more so, in a sense: the middle line would stand out even more, and yes that I agree that would bother me. I don’t find this very compelling, though, since I’d find all three lines more readable with parens around all the tuples, which would prevent this additional glare.

I couldn’t quickly out-comment like this anymore:
tests = test1, #test2, test3

Yes, that’s a valid point. Personally, I do highly value the ability to comment out parts of lists and tuples quickly; if there’s a significant possibility of wanting to do that, I’d write it as the following, which (to me) is the best of all worlds: good readability and good editability/tweakability, and wouldn’t be hurt by the current proposal:

tests = (
  test1,
  #test2,
  #test3,
)

If it applies to targets as well, I couldn’t do for value, in query_results: anymore and it would reduce consistency with loops like for x, y in points:. If it doesn’t apply to targets, then we lose consistency between targets and tuples.

Similarly to your first example, this is already inconsistent with for x,y in points: because of the requirement of the trailing comma, and I’d find it far more readable (the comma would be harder to miss) if parens were required: for (value,) in query_results:. So I don’t find this compelling as an argument against the current proposal; on the contrary, this example looks like evidence in favor of the proposal, to me.

=========

Nov '22 @ AndersMunch wrote:

There’s a nice example of that in test_functools.py . TestLRUPy.cached_func works exactly like this.

I tried to follow this link to see the example in question, and failed to find it, but I’m guessing that both (1) the code would be more readable if the 1-tuple were simply parenthesized; then everyone wins; and (2) the code really needs a comment.
Then @storchaka replied, invoking Chesterton’s Fence and the fact that these are expert coders so we should assume they know something we don’t. But it seems to me that the need to invoke Chesterton’s Fence implies the code was lacking needed comments, making the argument pretty weak, and the “expertness” of these coders pretty unimpressive and questionable, to me.

But, as I said, I didn’t actually find the code snippet in question, so I could be mistaken about some or all of my assumptions about the details of this example. If anyone would care to actually post the snippet in question, with explanation of what we think the “expert coders” had in mind, that might be helpful.

Which I would take to mean that, when the code was written, it was deemed obvious enough to not need it - that is, that the trailing comma was itself significant, without the need for a comma.

The need for comments is fairly subjective. I often see novice programmers adding comments onto core language features like “first, *rest = get_items() # split off the first item into its own variable” (synthesized example but I’ve seen a lot of things like this); more experienced programmers wouldn’t need that, but might annotate a slightly more complex idiom, like “while (data := sock.recv()): # an empty read means the socket is closed”; and so on. Which means one person can look at code and be confused, and wonder why there’s no comment, while another looks at it and understands it just fine, and wouldn’t even expect to see a comment there.

I can’t say for sure if that’s what happened, but it definitely is possible.

No, because it will be a different test case. The case of static methods is already covered by cached_staticmeth.

But it will now test a different case. The case of methods is already covered by cached_meth. We need to test the case of module level functions.

When I wrote this code in 2015, I didn’t expect it to cause confusion. To me, it was quite clear and the most natural way to write it, and any additions were unnecessary. It doesn’t seem like to confuse other core developers either.

If you want me to stop writing tuples like that because not everybody is familiar with basic syntax, then please also don’t use such words that not everybody is familiar with :-). (Not really, but I hope you get my point.)

About 1, 2 and 3, already being inconsistent: Meh, maybe a little. I’d say it depends on how you think of it. Something like “one comma to make it a tuple, more to separate elements” consistently describes both cases.

About the out-commenting example: Yes, sometimes I do that. But all those extra lines shove other lines off the screen, which is a disadvantage.