pythoniku
pythoniku

Reputation: 3662

Strange runtime error while iterating a dictionary

I ran the this block of code and get errors like below:

Traceback (most recent call last):
  File "urllister.py", line 26, in <module>
    for k in l: print k,"points to",l[k],"\n"
RuntimeError: dictionary changed size during iteration

The only thing I do is printing in the for loop at line 27

from sgmllib import SGMLParser

class URLLister(SGMLParser):
    def reset(self):
        SGMLParser.reset(self)
        self.data = []
    def start_a(self, attrs):
        href = [v for k , v in attrs if k == 'href']
        if href:
            self.data.extend(href)

if __name__ == '__main__':
    import urllib
    sock = urllib.urlopen("http://diveintopython.org")

    parser = URLLister()
    html = sock.read()

    parser.feed(html)

    sock.close()
    parser.close()
    for url in parser.data: print url
    l = locals()

    for k in l:
        print k,"points to",l[k],"\n"

Upvotes: 1

Views: 560

Answers (3)

duanev
duanev

Reputation: 964

The reason for this is that you loop introduces a new local variable, k, which means that your dictionary of local variables is changed in the loop.

The easiest solution is to define k before the loop so that locals() doesn't change once the loop has started.

k = 0
l = locals()

for k in l:
    print k,"points to",l[k],"\n"

Upvotes: 0

nonsleepr
nonsleepr

Reputation: 811

The reason for the error is that Python thinks, since you access the dict by key, you could change the dict, which is restricted here. To avoid this error, you can use get method and your statement will look like this then:

for k in l:
    print k,"points to",l.get(k),"\n"

Upvotes: 0

Gareth Latty
Gareth Latty

Reputation: 88997

The reason for this is that you loop introduces a new local variable, k, which means that your dictionary of local variables is changed in the loop.

The easiest solution (if you really need to do this, although it's a sign of a bad idea, generally) is to copy the dictionary - e.g: l = dict(locals()). This way the original being updated won't cause problems.

Upvotes: 10

Related Questions