`For x in locals():` -- RuntimeError: Why does locals() change size?
<p>I have a function and want to get the arguments passed to it. I tried achieving this via <code>locals()</code>, but I end up getting the keys of <code>locals()</code>, not the value-pairs:</p>

<pre><code>&gt;&gt;&gt;def print_params(i,j,k):
    for x in locals():
        print(x)
&gt;&gt;&gt;print_params('a','b','c')
j
i
k     #&lt;--I want to get back 'a','b','c'.
</code></pre>

<p>I'd like to get the values instead of the keys, from <code>locals()</code>.</p>

<p>With a normal dict, I know I can do this:</p>

<pre><code>&gt;&gt;&gt; m = {
... 'a' : 'b',
... 'y' : 'z'}
&gt;&gt;&gt; m
{'a': 'b', 'y': 'z'}
&gt;&gt;&gt; for x in m:
...     print(x)
...
a      # &lt;--Keys
y
&gt;&gt;&gt; for x in m:
...     print(m[x])
...
b      # &lt;--Values
z
</code></pre>

<p>But, if I try this with <code>locals()</code>, it creates a RuntimeError. </p>

<pre><code>&gt;&gt;&gt; def print_args(i,j,k):
...     for x in locals():
...         print(locals()[x])
...
&gt;&gt;&gt; print_args('a','b','c')
b                          # &lt;--Got one!
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  File "&lt;stdin&gt;", line 2, in y
RuntimeError: dictionary changed size during iteration
</code></pre>

<p>Can someone explain what's happening? From the single value I got to print (before it errors out), I can see that the error arises when the loop attempts to iterate to the next element of <code>locals()</code>; then, as the dict has been modified, it loses its place. I can't make sense of why the dictionary size should change, though. I'm inferring that, on each pass through the <code>for</code> loop, the variable <code>x</code> is destroyed, then re-created for the next pass through the loop. However, this seems odd, since I would think it'd be more efficient to keep <code>x</code> "alive" and just re-assign it to the new value on each iteration. </p>

<p>Ultimately, I guess I could just do <code>local_args = locals()</code>, but I'm still curious as to what exactly is happening that prevents me from simply looping through <code>locals()</code>. I'm not sure if I'm right about <code>x</code> being destroyed/recreated; if I am, I have to wonder why that is, and if I'm not, then I'm even more curious as to what's happening.</p>

<blockquote>
  <p>Can someone explain what's happening? From the single value I got to print (before it errors out), I can see that the error arises when the loop attempts to iterate to the next element of locals(); then, as the dict has been modified, it loses its place. I can't make sense of why the dictionary size should change, though. I'm inferring that, on each pass through the for loop, the variable x is destroyed, then re-created for the next pass through the loop. However, this seems odd, since I would think it'd be more efficient to keep x "alive" and just re-assign it to the new value on each iteration. </p>
</blockquote>

<p>The variable <code>x</code> is created only once, but it is not created until after you begin to iterate over <code>locals()</code>, because the source iterable of the <code>for</code> loop is evaluated before anything is assigned to the loop variable.  The error message, however, is raised by the dict itself (or rather, its iterator): it "notices" when something is trying to iterate it and it has changed since its last iteration.  So what happens is:</p>

<ol>
<li><code>locals()</code> is evaluated and gives you a dict</li>
<li>the <code>for</code> loop creates an iterator over the dict and gets the first element</li>
<li>a new local <code>x</code> is created and set to that first element</li>
<li>on the next loop iteration, the <code>for</code> loop tries to get another element from the dict iterator</li>
<li>the dict iterator notices that the underlying dict has a new element (<code>x</code>) since the last iteration, so it raises the error.</li>
</ol>

<p>A simple workaround is to create the variable <code>x</code> with some dummy value before the loop.  Then it will already exist before you ever access <code>locals()</code>, and there will be no creation of new variables during the loop:</p>

<pre><code>def print_args(i,j,k):
    x = None
    for x in locals():
        print(locals()[x])

&gt;&gt;&gt; print_args('a', 'b', 'c')
a
x
c
b
</code></pre>

<p>Notice, of course, that you will also get <code>x</code> itself during this iteration.</p>

<p>As others have mentioned in the comments, it's not really clear why you're doing this at all.  <code>locals()</code> is a rather slippery beast and usually, given some practical task you're trying to accomplish, there's a better way to do it without using <code>locals()</code>.</p>

python iteration