Reputation: 5474
From python wiki
Multiple Element Tuples
In Python, multiple-element tuples look like:
1,2,3
...
but again, it is the commas, not the parentheses, that define the tuple.
Oh, really?!
Then why:
>>> tuple((((((1, 2, 3)))))) # creates a valid tuple
# (1, 2, 3)
>>> tuple(1, 2, 3, ) # But not here
# TypeError: tuple() takes at most 1 argument (3 given)
More seriously, I don't get why the parenthesis was not chosen over the commas?
Because I think it would create a paradox when:
>>> 1, # is a valid tuple
# (1,)
>>> tuple([1]) # Or this
# (1,)
>>> tuple(1) # But not this one
# TypeError: 'int' object is not iterable
However, if you consider that parenthesis were always in charge of instantiating a tuple
, all of the problems with instantiating tuple
with multiple items are gone.
e.g. in my imaginary world:
>>> (1, 2, 3) # stay valid
# (1, 2, 3)
>>> (1) # is newly valid
# (1)
>>> () # stay valid
# ()
>>> 1,
# TypeError: int() takes exactly 1 argument (2 given)
I know this is a well-known feature and I'm already sorry if it a duplicate. I have found lots of similar topics about how tuple worked, but none explaining in details why this feature was created like that.
I am also aware that this topic could be closed as opinion-based, but I am mostly interested in technical reasons (if any), or at least historical reasons.
Thank you
Upvotes: 5
Views: 1482
Reputation: 226396
This is an artifact of the grammar.
The terms separated by commas are a building block for tuples, lists, and sets depending on whether they are wrapped by square brackets, curly braces, or nothing at all.
The chief challenge when specifying a grammar is balancing multiple competing uses of the same characters. Commas separate parts of lists, tuples, dicts, and sets. Commas also separate arguments in function calls. Trailing commas are allowed for both uses (and are required for tuples of length one). Likewise, parentheses have multiple uses including function calls and grouping for arithmetic expressions. The period serves as a decimal point and for the getattribute operator.
Upvotes: 11
Reputation: 78554
Usually, parens do not serve anything more than grouping, but when they appear after a callable, they have a different connotation than just grouping expressions; Python unlike, say Haskell, requires those parens to make the call.
In the following example, the outer pair of parens are bound to the function call (language construct), while the nested ones group the inner expression (the function arguments(s)) as a tuple:
>>> tuple((1, 2, 3))
(1, 2, 3)
Essentially, the tuple is created by the comma(s).
Upvotes: 2
Reputation: 476740
The reason why tuple(..)
does not take multiple arguments, is because there can be confusion between (1) a single element with an iterable that should be converted to a tuple, and (2) multiple arguments.
Say you call tuple with a single iterable element, then there can be confusion whether Python should construct a tuple with one element: the iterable; or a tuple that is constructed based on the given iterable. The designers of Python chose the latter. As is specified in the documentation:
tuple(iterable)
This is reasonable since then one can write:
tuple(x*x for x in somelist if x%2)
For instance to construct a tuple with squares of odd elements of the somelist
.
In your first example:
tuple((((((1, 2, 3))))))
You have constructed a tuple (1, 2, 3)
. Now you pass that tuple to the tuple constructor as the only parameter. Since a tuple is an iterable, you thus construct a tuple based on the only iterable you pass.
Your expression:
tuple(1, 2, 3, )
However raises an error, since you provide more elements than the only one that you can and should pass.
Next you have the tuple literal. A literal is a comma separated list of expressions. It constructs a tuple with the given elements. In case you would however call a method without additional parenthesis, there is confusion between (1) a tuple literal; and (2) multiple arguments you pass to the method.
There are other such "grammar" aspects in Python. For instance if you pass a generator to a function with multiple arguments, the generator needs to be enclosed by parenthesis as well.
Upvotes: 3