Issue Overview
In Python, there’s an ambiguous behavior when dealing with tuples containing a single element. Specifically, assigning a value like python = 1, results in python being treated as a tuple (1,). This behavior can be non-intuitive, especially for beginners, and lacks an explicit error message, potentially leading to unintended bugs.
Proposed Solution
Introduce a clearer error message or warning when creating single-element tuples.
Enhance the documentation on this behavior to prevent confusion among new Python users.
Expected Outcome
Developers will have a clearer understanding of Python’s behavior when creating single-element tuples.
Reduce the risk of accidental errors among beginners due to this unique syntax.
Additional Information
This issue is particularly confusing for those new to Python.
Current Python documentation does not sufficiently explain this behavior.
There are an untold number of programs that rely on this behavior. It certainly cannot become an error, so the only choice would be to make it a warning forever. And I don’t think that’s a good idea: most of the people who see these warnings couldn’t do anything about it.
I think this is best left to linters to warn about.
It’s not ambiguous; it does the same thing in every situation. It’s also by design. It lacks an explicit error message, yes. It lacks any kind of error or warning message, because it is considered correct code. It’s a natural consequence of a) the fact that a comma is needed to indicate a tuple (since letting (x) mean anything different from just x would cause all kinds of other problems) plus b) the convenience of not requiring parentheses for a tuple (which, in turn, is why you can write x, y = y, x without parentheses).
Some may find it not intuitive. But I ask: what else might one expect it to do?
It’s also fairly hard to do this by accident. , isn’t a common typo for ;, for example, and “you don’t need semicolons” is one of the big selling points of Python, so beginners coming from other language backgrounds should be trained out of the bad habit as quickly as possible. I suppose that in the specific example of 1,, that could be a typo for 1. - I recommend always typing at least one explicit decimal digit for floating-point values, thus, 1.0. That’s how you write it in a math classroom, anyway.
There is no error, and I do not see any ambiguity in the example. However, in the section where tuples are defined, I think the phrase about one-item tuples, " The trailing comma is required only to create a single tuple (a.k.a. a singleton)", would be improved by replacing “single” with “one-item”, as “single tuple” really means “one tuple (of whatever length)”. I also think a minimal example, such as “such as 1,” would help. I would also replace ‘;’ with ‘.’ and make the second phrase a separate sentence. The result would be " A trailing comma is required only to create a one-item tuple (a.k.a. a singleton), such as 1,. (I believe the .rst markup would need double backticks instead of single backticks for the example.)
EDIT: I will look at the tutorial tomorrow. (Karl’s first post with a link (thanks) was posted while I wrote the original version of this line.)
This is something that linters could choose to respond to, but making it an error would break far too much valid code, not to mention that (aside from the empty tuple) it’s never the parentheses that create a tuple.
This PR edits the one-item tuple doc to be clearer. The tutorial looked fine as it already said more and included such in its code examples. The PR and 2 backports are merged.
Sensible improvements! I love watching the cpython commits. I’ve learned a lot.
I’m sure it’s been discussed- but why not create an explicit syntax for a one-item tuple, that’s easier on the eyes than a dangling comma?
Going further; an opt-in way to warn or reject the comma syntax on a module or package would be welcome. I’d use it.
The comma is a beautiful thing however it’s working overtime here.
A problem example when writing: dataclasses have no commas after fields while a traditional init does; so cut and paste in a big project with a mix of class declaration styles can easily introduce an erroneous comma.
When reading: Documentation/samples for pickle’s reduce often show a one-item tuple with the telltale comma and lots of parentheses, which is offf-putting and obfuscating to beginners. Something clean that jumps out and says “I’m a one-tuple” would really be nice.
Python has embraced aesthetics from the beginning, and that’s a big part of its success.
Beginners, intermediates and experts have different aesthetic views. (The Oxford comma is a similar debate )
I tried to learn Scala but they overused the underscore.
I tried to like yaml but they use too many one-character idioms.
Python is beautiful. I think the one-tuple comma is fine but an explicit syntax that’s not reliant on commas and parentheses might be better for many people. Non-experts of course.
I can create my own one-item tuple constructor (and I think I will) but there are advantages to standard official syntax, to help non-experts with reading, writing and understanding.
I don’t understand. How do the parentheses and trailing comma not “jump out”? What could it, in principle, look like instead that is more evident? Parentheses without a trailing comma are already needed for expression grouping; square brackets already mean a list; braces already mean a dict or set; angle brackets are already comparison operators and would be ferociously hard to parse any other way at the same time. If a trailing comma isn’t acceptable, then we can’t fix the problem with an element separator, only with delimiters for the tuple; but every sensible option is already used. And at any rate I don’t understand why any such option would be more visually distinctive.
Better IMO to use a variable-args constructor, then you can have a uniform appearance:
def tuple_of(*args):
return args
I strongly doubt that tuple(x, single=True) is any better than tuple([x]) or tuple((x,)).
Objectively, it replaces an unambiguous syntactic construct with a function call whose semantics can be changed at runtime by rebinding the name tuple.
It also makes the existing type responsible for too many separate tasks. Currently, tuple does one thing: constructs an instance of tuple using an iterable value. Since were already increasing the amount of typing, a class method like
tuple.from_items(x)
# 6 characters longer than
# tuple(item=x)
# which is 9 characters longer than
# (x,)
would be more explicit and still generalize to tuples of arbitrary size:
The barrier for new syntax and forms, including behaviors for built-in types, is rightly quite high.
A successful change proposal requires stronger justification than “it looks nice to me”. Aesthetics are important, but they are too subjective, on their own, to provide us with directions for the language. You say “I like it” and I say “I don’t like it” and the conversation goes nowhere because we aren’t really sending much information back and forth.
There are already two ways to do it:
x = 1,
y = (1,)
This would add a third.
A larger core language isn’t necessarily better. Often it’s worse just by virtue of being larger. Python is pretty large already, as a language (not the biggest, but certainly not the smallest). Sometimes I wish it were smaller. I rarely wish for it to be bigger.
Python has too much history / existing code for a change to tuple syntax make sense. There should be one-- and preferably only one --obvious way to do it. Adding another single tuple construction option would just confuse a new Python developer who comes across code using the existing syntax.
But let’s not pretend for a moment that the x = (4,) syntax is not just weird from a natural language (English) standpoint. It looks like a typo. It looks like a superfluous comma analogous to the trailer in (3,4,5) == (3,4,5,) .
When I write tuples my mantra is the comma makes the tuple, because I’ve burned myself many times forgetting it.
So let’s keep the existing syntax with empathy and kindness for new developers tripped up by it.