os.path.walk not pruning descent tree (and I'm not happy with that behavior?)

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Mon May 28 01:36:08 EDT 2007


En Sun, 27 May 2007 22:39:32 -0300, Joe Ardent <ardent at gmail.com> escribió:

> Good day, everybody!  From what I can tell from the archives, this is
> everyone's favorite method from the standard lib, and everyone loves
> answering questions about it.  Right? :)

Well, in fact, the preferred (and easier) way is to use os.walk - but  
os.path.walk is fine too.

> Anyway, my question regards the way that the visit callback modifies
> the names list.  Basically, my simple example is:
>
> ##############################
> def listUndottedDirs( d ):
>     dots = re.compile( '\.' )
>
>     def visit( arg, dirname, names ):
>         for f in names:
>             if dots.match( f ):
>                 i = names.index( f )
>                 del names[i]
>             else:
>                 print "%s: %s" % ( dirname, f )
>
>     os.path.walk( d, visit, None )
> ###############################

There is nothing wrong with os.walk - you are iterating over the names  
list *and* removing elements from it at the same time, and that's not  
good... Some ways to avoid it:

- iterate over a copy (the [:] is important):

for fname in names[:]:
   if fname[:1]=='.':
     names.remove(fname)

- iterate backwards:

for i in range(len(names)-1, -1, -1):
   fname = names[i]
   if fname[:1]=='.':
     names.remove(fname)

- collect first and remove later:

to_be_deleted = [fname for fname in names if fname[:1]=='.']
for fname in to_be_deleted:
   names.remove[fname]

- filter and reassign in place (the [:] is important):

names[:] = [fname for fname in names if fname[:1]!='.']

(Notice that I haven't used a regular expression, and the remove method)

-- 
Gabriel Genellina




More information about the Python-list mailing list