Summary: The argument in list(arg) must be iterable. The argument in str(arg) can be anything. Further, in [ a, b, c, d ] the content of the literal must be read by the Python parser as a Python expression. But in "this and that" the content need not be a Python expression.

Hi David

I find your suggestion a good one, in that to respond to it properly requires a good understanding of Python. This deepens our understanding of the language. I'm going to follow on from a contribution from Brendan Barnwell.

Please consider the following examples

Similarity.
    >>> list( x*x for x in range(5) )
    [0, 1, 4, 9, 16]
    >>> [ x*x for x in range(5) ]
    [0, 1, 4, 9, 16]

Difference.
    >>> tmp = (x*x for x in range(5)) ; list(tmp)
    [0, 1, 4, 9, 16]
    >>> tmp = (x*x for x in range(5)) ; [ tmp ]
    [<generator object <genexpr> at 0x7fec02319678>]

Difference.
    >>> list( (x*x for x in range(5)) )
    [0, 1, 4, 9, 16]
    >>> [ (x*x for x in range(5)) ]
    [<generator object <genexpr> at 0x7fec02319620>]

Now consider ,
    >>> str( x * 2 for x in 'abc' )
    '<generator object <genexpr> at 0x7fec02319728>'

This last one genuinely surprised me. I was expecting 'aabbcc'. To understand this, first note the quote marks in the response. Next recall that str returns the string representation of the argument, via type(obj).__str__(obj).

My understanding of the situation is that the list comprehension [ x*x for x in range(5) ] is a shorthand for list( x*x for x in range(5) ). It works because list takes an iterable as its argument (if it has one argument). But str with one argument gives the string representation of an arbitrary object. Here's an example.

    >>> list(None)
    TypeError: 'NoneType' object is not iterable
    >>> str(None)
    'None'

Here's what Brendan wrote: The difference between your proposal and existing comprehensions is that strings are very different from lists, dicts, sets, and generators (which are the things we currently have comprehensions for).  The syntax for those objects is Python syntax, which is strict and can include expressions that have meaning that is interpreted by Python.  But strings can contain *anything*, and in general (apart from f-strings) their content is not parsed by Python.

In a nutshell: The argument in list(arg) must be iterable. The argument in str(arg) can be anything. Further, in [ a, b, c, d ] the content of the literal must be a Python expression, whereas in "this and that" the content need not be a Python expression.

I hope this helps.

Jonathan