I tried to create a tuple containing two float number. (4.0, 4.0), for example. However, as the two floats was the same, I wrote 4.0, * 2.
What I wanted to do can be written: (4.0,) * 2. In Python, multiply a tuple by an integer says to Python to concatenate this number of times the tuple with itself. So (4.0,) * 2 = (4.0,) + (4.0,) = (4.0, 4.0). OK.
What I did not want to do is 4.0 * 2 (without the comma). Indeed, this will multiply the float 4.0 itself by 2: 4.0 * 2 = 8.0. OK.
But none of these comportments happened. Instead of 8.0 or (4.0, 4.0), I got a
TypeError: 'int' object is not iterable
I am pretty surprized by this answer. How this syntax can lead to an iteration of 2 (which is the sole integer of this expression)?
It is matter of precedence, mixed with a wrong operator interpretation.
* (a multiplication) has a higher precedence than ,: 4.0, 4.0 * 2 = 4.0, (4.0 * 2) = (4.0, 8.0). In my expression, it cannot be understood as this, because nothing can be multiplyed by two: 4.0, <nothing> * 2. As a multiplication is a binary operator, it must have a value to the left, which must be 4.0, itself.
This is quite true… for the binary * operator. However, Python has a unary * operator, whose precedence is also higher than ,. This unary operator is used to expand an iterable in-place. This is often seen when we define or call a function with a variable number of arguments:
def min(first, *others): ...
data = tuple(4, 5, 6, 7)
min(*data)
It is this operator that is used in my expression. Python interprets 4.0, * 2 as 4.0, (*2), which says “a tuple, containing 4.0 as first element, followed by all elements contained in 2”. Effectively, an integer is not iterable, and Python complains about it.
As proof, we can compute this expression, which actually gives an iterable to the * unary operator:
>>> 4.0 , * ( 5.0 , 6.0 ) # equivalent of (4.0, (*(5.0, 6.0)))
(4.0, 5.0, 6.0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With