Removal of element from list while traversing causes the next element to be skipped

Paul Hankin paul.hankin at gmail.com
Tue Jan 29 23:49:09 CET 2008


On Jan 29, 4:34 pm, William McBrine <wmcbr... at users.sf.net> wrote:
> Look at this -- from Python 2.5.1:
>
> >>> a = [1, 2, 3, 4, 5]
> >>> for x in a:
>
> ...     if x == 3:
> ...         a.remove(x)
> ...     print x
> ...
> 1
> 2
> 3
> 5
>
> >>> a
> [1, 2, 4, 5]
>
> Sure, the resulting list is correct. But 4 is never printed during the
> loop!
>
> What I was really trying to do was this:
>
> apps = [name for name in os.listdir(ROOT) if
>         os.path.isdir(os.path.join(ROOT, name))]
>
> apptitles = {}
>
> for name in apps:
>     try:
>         app = __import__(name)
>     except:
>         apps.remove(name)
>     else:
>         apptitles[name] = getattr(app, 'TITLE', name.title())
>
> which worked fine, until I actually had a directory with no module in it.
> Then that directory was correctly removed from the list, but the _next_
> one was skipped, so its title was never assigned, which caused problems
> later in the program.

How about...
for name in apps:
    try:
        app == __import__(name)
        apptitles[name] = getattr(app, 'TITLE', name.title())
    except ImportError:
        pass

# Remove apps with no title, ie those that didn't import.
apps = [name for name in apps if apptitles.get(name)]

Alternatives for the last line would be 'apps = filter(apptitles.get,
apps)'
or 'apps = apptitles.keys()'.

--
Paul Hankin



More information about the Python-list mailing list