Why does "list()" necessitate that parentheses surround its arguments?

Question(s)

Why does the builtins.list() function necessitate that parentheses surround its arguments? An example is undermentioned:

  1. #!/usr/bin/env python3.14
    variable = builtins.list('1', '2')
    
  2. Traceback (most recent call last):
      File "<python-input-3>", line 1, in <module>
        variable = builtins.list('1', '2')
    TypeError: list expected at most 1 argument, got 2
    
  3. #!/usr/bin/env python3.14
    variable = builtins.list(('1', '2'))
    variable
    
  4. ['1', '2']
    

Answer(s)

As of +2025-01-30T13:35:42+00:00.

Related

The purpose of calling list() is to convert an iterable (note singular iterable) into a list. list(('1', '2')) gives it the tuple ('1', '2') which is one iterable so it’s allowed whereas list('1', '2') is two separate arguments so it is not.

Stick with the usual ['1', '2'] if you want to write a literal list.

2 Likes

And if list(a, b, ...) worked, it wouldn’t be possible to distinguish between list((a, b, c)) meaning “I want [a, b, c]” versus “I want [(a, b, c)]”.

2 Likes

Thanks, @bwoodsend.

Would tuple() work here as a replacement? That’d make it a little easier to read.

They are equivalent though, right?

Back in the really old days (Python 1.1, 1.2?) tuple and list used to accept multiple arguments. It was realized that was a bug though, and the API changed.

No, tuples and lists are different data types, generally used to represent different kinds of data. Two main differences spring immediately to my mind:

  1. Tuples are immutable, while lists are not.
  2. Tuples are generally better thought of like records or structs in other languages, while lists are generally treated more like arrays.

Tuples (and their named variant) often have elements of different types. So, you might record a tuple for a person like

person = ("Browne", "Jackson", 75)

If you wanted to keep information on another person, you’d create a new record.

person2 = ("Stills", "Stephen", 80)

Lists, on the other hand, might represent something like a bunch of test scores:

scores = ["A", "B", "A", "C", "F"]

If another person took the test for which the list recorded scores, you might simply append their test grade:

scores.append("A+")
3 Likes

What exactly do you mean by using tuple() as a replacement? Like, a replacement for what? You can’t do list(tuple('1', '2')) because tuple, like list, expects a single iterable argument, so tuple('1', '2') will fail in the same way as list('1', '2').

Yeah, that was a bit of a silly suggestion as a replacement. In summary, am I correct that parenthesis can declare an iterable in addition to declaring what code is executed first in a line, based upon context?

Not sure what you mean. Python could make list(a, b, ...) work and keep list((a, b, c)) meaning [a, b, c].

It can get a little tricky to use the list function to do that. Out of these four, the final one works:

>>> list((1, 2, 3))
[1, 2, 3]
>>> list((1, 2, 3),)
[1, 2, 3]
>>> list(((1, 2, 3)))
[1, 2, 3]
>>> list(((1, 2, 3),))
[(1, 2, 3)]
1 Like

Yes, parenthesis can create a tuple which is something you can iterate over. It is a somewhat overloaded piece of punctuation.

1 Like

@bwoodsend, thanks. That helps a lot. A shame that there’s no function or class to replace it (like there is sum() for +), since that’s not intuitive.


Regarding the aforementioned, do you recommend this for conciseness, or something else?

Yes, parentheses lead a tough life with their multitude of responsibilities.

  • enclosing function arguments
  • enclosing parameters within function definition headers
  • controlling evaluation order within expressions
  • sometimes used to define tuple literals within expressions
  • sometimes left open temporarily for continuing an expression over more than one line
  • and more …

Some of the above are actually related and consequential to each other, but we need not get into the details here. With their heavy load, parentheses may sometimes need the help of that little comma.

So, let’s give those hard-working delimiters and ourselves a break by foregoing the tuple here in favor of a list literal.

Another use of parentheses, external to Python - an emoticon :slight_smile:

1 Like

Note that list() creates a list from basically any iterable, not just tuples. A few non-obvious examples:

>>> list("abc")
['a', 'b', 'c']
>>> list(b"abc")
[97, 98, 99]
>>> list(dict(foo=123,bar=456))
['foo', 'bar']
>>> list(range(0,5))
[0, 1, 2, 3, 4]
1 Like

Are you familiar with the Zen of Python (import this)? From that:

There should be one-- and preferably only one --obvious way to do it.

The use of square brackets to define a list of some known elements is the “one obvious” way to do it. The list() builtin function is generally used to convert some other sequence or iterable to a list. Think a sequence object of a potentially variable number of elements. A quick example… Most of the time you just iterate over the return value of the range() builtin function:

for i in range(10):
   ... blah blah blah ...

Sometimes you need an actual list though. In this case, you use list() to generate the list object.

>>> range(10)
range(0, 10)
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1 Like

It could be defined to have different behavior when there’s one argument versus multiple, but I think that would confuse far more people than it helps. And there would be this confusing edge case when you wanted a list with one element in it.

1 Like

min and max already do that and I’ve never seen anyone confused by that. But it certainly wouldn’t help, as a list display is just better.

Since we have been wrangling with tuples, let’s also note that we do not always need parentheses to denote a tuple literal:

>>> seeing_double = "Doctor", "My Eyes"
>>> seeing_double
('Doctor', 'My Eyes')

We need the comma here to denote that this is to be a tuple with one item:

>>> interminable_wait = "Godot",
>>> interminable_wait
('Godot',)

In a tuple with more than one item, an extraneous comma at the end is no problem:

>>> musical_pun = "Tom", "Waits", "for", "No", "One",
>>> musical_pun
('Tom', 'Waits', 'for', 'No', 'One')

:grin:

1 Like

A perfect example showing why you should always surround your tuples with parens. :wink:

1 Like

I’m confused, why is that a good example?

@jamestwebber, I presume because it would be a builtins.str otherwise.