difference between range / len etc. when iterating over tuples
<p>One thing upfront: I am fairly now to the coding world so maybe my question is a bit stupid ... I was trying to write a function that returns the every other element of a tuple. The easiest way obviously is </p>

<pre><code>def oddTuples(aTup):
     return aTup[::2]
</code></pre>

<p>I tried to solve it differently by using the following code</p>

<pre><code>def oddTuples(aTup):
    newTup = ()
    for i in len(aTup):
        if i%2 != 0:
            newTup = newTup + (i,)
    return newTup
</code></pre>

<p>But that doesn't give me back anything at all.</p>

<p>I thought I (if used over <code>len</code>) gives back the position, so if <code>aTup = ((12, 34, 'abc', 'dfdf', 2340))</code> the return would be <code>newTup = ((12, 'abc', 2340))</code>.</p>

<p>What's the <code>i</code> iterating over when used with <code>range</code>, <code>len</code> or -in that case- while iterating over <code>for i in aTup:</code>?</p>

<p>Python's <code>for</code> loop is a <a href="https://en.wikipedia.org/wiki/Foreach_loop" rel="nofollow"><em>foreach</em> construct</a>; it'll loop over a sequence or iterable and bind the target variable (<code>i</code> in your case) to each element in that sequence one by one.</p>

<p>So for <code>for i in aTuple:</code>, with each iteration, <code>i</code> is bound to the next value from the tuple. If you used a <code>range()</code> object, then looping over that object would produce integers in the range, from start (defaulting to <code>0</code>) up to the end value minus 1 (the end value is excluded).</p>

<p>Your code, however, doesn't loop over <code>range()</code>; you try to loop over the result of <code>len(aTuple)</code>, which will be a <em>single integer</em>. That gives a <code>TypeError: 'int' object is not iterable</code> exception.</p>

<p>If you want to use the <a href="https://docs.python.org/3/library/stdtypes.html#ranges" rel="nofollow"><code>range()</code> type</a>, that's fine, but then you'll have to translate the index back into a value from <code>aTuple</code> by using indexing:</p>

<pre><code>def oddTuples(aTup):
    newTup = ()
    for i in range(len(aTup)):
        if i%2 != 0:
            newTup = newTup + (aTup[i],)
    return newTup
</code></pre>

<p>Here <code>aTup[i]</code> produces the value at index <code>i</code>; where <code>i</code> is so index <code>1</code>, <code>3</code>, etc, so you get every odd element. Note that this <em>differs</em> from <code>aTup[::2]</code>, which starts at <code>0</code> and includes every even-numbered element! Python starts counting at <code>0</code>, so take that into account when counting out elements.</p>

<p>You can avoid having to index back in by using the <a href="https://docs.python.org/3/library/functions.html#enumerate" rel="nofollow"><code>enumerate()</code> function</a>; for every element in a sequence it'll produce a tuple with an ever-increasing index number. Let's use that to fix the odd-even issue, mixing in some <code>+=</code> augmented assignment too:</p>

<pre><code>def oddTuples(aTup):
    newTup = ()
    for i, value in enumerate(aTup):
        if i % 2 == 0:
            newTup += value,
    return newTup
</code></pre>

<p>You don't really need the <code>(...)</code> parentheses here either, tuples are formed by commas (except for the empty tuple, and use parentheses when the comma could mean something else, like in a function call).</p>

python for-loop range iteration tuples