Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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...

Addendum

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.)

There is a syntax, in python ≥ 3.5, that "just works" but nevertheless I would like some understanding.

like image 780
gboffi Avatar asked Nov 18 '16 11:11

gboffi


People also ask

What is a starred expression?

The starred expression will create a list object, although we start with a tuple object. Starred expressions can be used with more than just tuples, and we can apply this technique for other iterables (e.g., lists, strings).

Can use starred expression only as assignment target?

Starred expressions are only allowed as assignment targets, using them anywhere else (except for star-args in function calls, of course) is an error.


2 Answers

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:

>>> '%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.

Update: since python 3.6, you could also use string interpolation - f-strings! These are described in PEP-498, and some examples can be found in Python documentation.

Starred Expressions

There are many more uses to starred expression than just creating a new list/tuple/dictionary. Most of them are described in PEP 3132, and PEP 448.

All of them come down to two kinds:

R-value 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 has already been covered to a substantial extent in another Stack Overflow question.

like image 93
Błażej Michalik Avatar answered Sep 21 '22 01:09

Błażej Michalik


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,) 
like image 30
Marcus Müller Avatar answered Sep 22 '22 01:09

Marcus Müller