Why can't I use a starred expression?
Why can't I use a starred expression?
My code
$ python
Python 3.5.2 |Continuum Analytics, Inc.| (default, Jul 2 2016, 17:53:06)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> a = (1, 2)
>>> '%d %d %d' % (0, *a)
'0 1 2'
>>> '%d %d %d' % (*a, 3)
'1 2 3'
>>> '%d %d' % (*a)
File "<stdin>", line 1
SyntaxError: can't use starred expression here
>>>
My question, why?
In a more serious tone: I'd like an answer, or a reference, that details all the ins and outs of using a starred expression, as it happens that I am sometimes surprised from its behaviours...
To reflect some of the enlightening comments that
immediately followed my question I add the following code
>>> '%d %d' % (, *a)
File "<stdin>", line 1
'%d %d' % (, *a)
^
SyntaxError: invalid syntax
>>> '%d %d' % (*a,)
'1 2'
>>>
(I had tried the (, a)
part before posting the original question but I've omitted it 'cause the error was not related to the starring.)
(, a)
There is a syntax, in python ≥ 3.5, that "just works" but nevertheless I would like some understanding.
(*a,)
@MarcusMüller extending unpacking (for
*
and **
on the RHS) was 3.5. And the correct syntax is (*a,)
...– Jon Clements♦
Nov 18 '16 at 11:38
*
**
(*a,)
@JonClements I know. That's why I asked gboffi above to clarify the python version she/he uses!!
– Marcus Müller
Nov 18 '16 at 11:39
Take a look at the "Unpacking Iterables" documentation on SO stackoverflow.com/documentation/python/809/…
– pylang
Nov 18 '16 at 12:01
Interestingly, the
format()
function does not have this issue, i.e. ':d :d'.format(*a)
--> '1, 2'
. The issue appears related to the %
string formatter.– pylang
Nov 18 '16 at 12:08
format()
':d :d'.format(*a)
'1, 2'
%
3 Answers
3
It's because this:
(a)
Is just a value surrounded by parenthesis. It's not a new tuple object. So your expression:
>>> '%d %d' % (*a)
will get translated to:
>>> '%d %d' % * a
which is obviously wrong in terms of python syntax.
In order to create a new Tuple, with one expression as an initializer, you need to add a ',
' after it:
,
>>> '%d %d' % (*a,)
Note: unless a
is a generator, in this particular situation you could just type:
a
>>> '%d %d' % a
Also, if I may suggest something: you could start using new-style formating expressions. They are great!
>>> " ".format(*a)
You can read more about them in those two paragraphs of python documentation, also there is this great website. The line above uses argument unpacking mechanism described below.
There are many more uses to starred expression than just creating a new list/tuple/dictionary. Most of them are described in this PEP, and this one
All of them come down to two kinds:
RValue unpacking:
>>> a, *b, c = range(5)
# a = 0
# b = [1, 2, 3]
# c = 4
>>> 10, *range(2)
(10, 0, 1)
Iterable / dictionary object initialization (notice that you can unpack dictionaries inside lists too!):
>>> [1, 2, *[3, 4], *[5], *(6, 7)]
[1, 2, 3, 4, 5, 6, 7]
>>> (1, *[2, 3], *"a": 1)
(1, 2, 3, 'a')
>>> "a": 1, **"b": 2, "c": 3, **"c": "new 3", "d": 4
'a': 1, 'b': 2, 'c': 'new 3', 'd': 4
Of course, the most often seen use is arguments unpacking:
positional_arguments = [12, "a string", (1, 2, 3), other_object]
keyword_arguments = "hostname": "localhost", "port": 8080
send(*positional_arguments, **keyword_arguments)
which would translate to this:
send(12, "a string", (1, 2, 3), other_object, hostname="localhost", port=8080)
This topic was already covered in great extent in another Stack Overflow question.
The interesting part is if you read the specification. I don't it says that you just can drop parentheses like that.
– skyking
Nov 18 '16 at 11:54
@skyking Have look at the edit. :)
– Błażej Michalik
Nov 18 '16 at 11:59
My question, why?
Because your python syntax doesn't allow that. It's defined that way, so there's no real "why".
also, it's unnecessary.
"%d %d" % a
would work.
So, you'd need to convert your expansion to a tuple – and the right way of doing that would be, as pointed out by Lafexlos, be
"%d %d" % (*a,)
Considering the OP was showing successful input/output using
*a
and was asking about why (*a)
specifically didn't work - it's safe to assume they were using 3.5 or else there'd be errors in the original code posted and not just for that specific case.– Jon Clements♦
Nov 18 '16 at 11:42
*a
(*a)
@JonClements haaaah you're right. I need to change the answer.
– Marcus Müller
Nov 18 '16 at 11:48
@skyking just saw that, and tagged the question accordingly. Thanks!
– Marcus Müller
Nov 18 '16 at 11:49
Re
"%d %d" % a
, my real use case involves a generator expression…. In the question I wanted to keep things simple and, moreover, I really want to know the details of unpacking– gboffi
Nov 18 '16 at 12:06
"%d %d" % a
It's because:
>>> '%d %d' % (*a)
Can be just:
>>> '%d %d' %a
Of course then able to do:
>>> '%d %d' % (*a,)
But then:
>>> (*a,)==a
True
>>>
Or you can do:
>>> '%d %d' % [*a]
But then:
>>> [*a]
[1, 2]
>>> a
(1, 2)
>>>
So:
>>> tuple([*a])==a
True
Thanks for contributing an answer to Stack Overflow!
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy
(*a,)
Note the comma at the end to make it tuple.– Lafexlos
Nov 18 '16 at 11:37