2

How do the following work?

>>> 3*[2]
>>> [2,2,2]
>>> [2]*3
>>> [2,2,2]

I understand that * is the positional expansion operator. Since [2] is a list with a single item, I don't see how 3*[2] expands to anything meaningful, I'd expect a SyntaxError, but that's not the case.

I'm having a hard time searching for an existing answer, all I find are references to *args and **kwargs for passing variadic parameter lists, which don't quite answer my question.

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
ash
  • 3,354
  • 5
  • 26
  • 33
  • 8
    `*` is also the multiplication operator, which has special behavior for sequences. See [the documentation](https://docs.python.org/2/library/stdtypes.html#sequence-types-str-unicode-list-tuple-bytearray-buffer-xrange). – BrenBarn Mar 27 '15 at 17:15
  • @BrenBarn How does it known to differentiate between multiplication and expansion in this case? – ash Mar 27 '15 at 17:17
  • not an expansion operator, just a multiplication operator – Julien Spronck Mar 27 '15 at 17:18
  • @ash: The `*args` argument expansion can only be used inside the parentheses of a function call. There's no function call here. It "knows" to use multiplication here just like it knows to use multiplication when you write `2*3` and get 6. – BrenBarn Mar 27 '15 at 17:19
  • @BrenBarn ah, perfect, that's exactly what I wanted to know. Thanks, dude! – ash Mar 27 '15 at 17:20
  • @ash Look into [Python's special methods](https://docs.python.org/2/reference/datamodel.html#specialnames) to understand how operators work on types. – Shashank Mar 27 '15 at 17:22
  • In stuff like `3*[2,3]` It's actually multiplication that is done on the list, not expansion. This can be seen if you consider that `3*[2,3]` is just a shorthand for writing `l = [2,3]; l+l+l`. What he is talking about is the * expansion syntax like `*args` and doing stuff like `zip(*somesequence)`. That is expansion. Or another name for it would be *explicit packing and unpacking*. – Shashank Mar 27 '15 at 17:26

1 Answers1

16

* is the multiplication operator. All Python sequences support multiplication. See the Sequence Types documentation:

s * n, n * s
n shallow copies of s concatenated

Note that the copies are shallow; any nested mutable types are not recursively copied too. This can lead to suprising results:

>>> nested = [[None]] * 5
>>> nested
[[None], [None], [None], [None], [None]]
>>> nested[0].append(42)
>>> nested
[[None, 42], [None, 42], [None, 42], [None, 42], [None, 42]]

There is just one nested [None] list, referenced 5 times, not 5 separate list objects.

The *args and **kw variable argument syntax only has meaning in a function definition or in a call (so callable_object(<arguments>)). It doesn't apply here at all. See What does ** (double star) and * (star) do for parameters? for more detail on that syntax.

Sequence types overload the * operator through the object.__mul__() and object.__rmul__() methods (when being the left or right operand in the expression), see Emulating container types for documentation on what hooks sequence types typically implement.

Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 5
    You are too damn fast :/ Whenever I get to a question you already fixed code syntax and answered the question with perfect examples and links to documentation. Oh well, that's a compliment, so stay so helpful! – syntonym Mar 27 '15 at 17:22
  • I think it is worth mentioning the `__mul__` method as it seems to be the point of confusion. Python can differentiate multiplication and list expansion because of the objects used in an expression containing an asterisk. If your object is a list, Python used the `__mul__` function in the list class. Same thing for strings and integers. It all depends on the objects used. – Malik Brahimi Mar 27 '15 at 17:28
  • @MalikBrahimi: added, including the `__rmul__` alternative for lists in the right-hand-side of the expression. – Martijn Pieters Mar 27 '15 at 17:34
  • @Malik well, in a couple of cases `__rmul__` will end up being called... probably a bit TMI for the OP right now :p – Jon Clements Mar 27 '15 at 17:34