2010-06-09 4 views
0

Документация os.walk (http://docs.python.org/library/os.html? Highlight = os.walk # os.walk), говорит, что я могу пропустить обход нежелательных каталогов, удалив их из списка директорий. Явный пример из документов:Ошибка в os.walk Python?

import os 
from os.path import join, getsize 
for root, dirs, files in os.walk('python/Lib/email'): 
    print root, "consumes", 
    print sum(getsize(join(root, name)) for name in files), 
    print "bytes in", len(files), "non-directory files" 
    if 'CVS' in dirs: 
     dirs.remove('CVS') # don't visit CVS directories 

Я вижу другое поведение (используя ActivePython 2.6.2). А именно для кода:

>>> for root,dirs,files in os.walk(baseline): 
...  if root.endswith(baseline): 
...    for d in dirs: 
...      print "DIR: %s" % d 
...      if not d.startswith("keep_"): 
...        print "Removing %s\\%s" % (root,d) 
...        dirs.remove(d) 
... 
...  print "ROOT: %s" % root 
... 

Я получаю результат:

DIR: two 
Removing: two 
DIR: thr33 
Removing: thr33 
DIR: keep_me 
DIR: keep_me_too 
DIR: keep_all_of_us 
ROOT: \\mach\dirs 
ROOT: \\mach\dirs\ONE 
ROOT: \\mach\dirs\ONE\FurtherRubbish 
ROOT: \\mach\dirs\ONE\FurtherRubbish\blah 
ROOT: \\mach\dirs\ONE\FurtherRubbish\blah\Extracted 
ROOT: \\mach\dirs\ONE\FurtherRubbish\blah2\Extracted\Stuff_1 
... 

WTF? Почему не удалили \\mach\dirs\ONE? Это явно не начинается с «keep_».

ответ

5

Потому что вы изменяете список dirs, итерации по нему. ONE был просто пропущен и никогда не просматривается. Сравнить:

>>> a = [1, 2, 3] 
>>> for i in a: 
    if i > 1: 
     a.remove(i) 


>>> a 
[1, 3] 
+0

То, что он сказал. Обратите внимание на пример, что они изменяют список 'dirs' ПЕРЕД тем, как они перебирают его. – jathanism

+0

@jathanism: они вообще не перебирают 'dirs';) – SilentGhost

+0

Ну нет в примере кода, нет. Но предполагается, что это было бы, пожалуй, больше. – jathanism

2

Вы не снимаете его из списка dirs. Если бы вы были, вы увидите распечатку «Удаление», не так ли?

Изменить for d in dirs на for d in list(dirs) чтобы безопасно удалить элементы из списка dirs, итерации по нему.

Или вы могли бы просто написать:

dirs[:] = [d for d in dirs if not d.startswith("keep_")] 
+0

Ваше первое предложение, используя 'list (dirs)', работало, но понимание списка не повлияло на какие-либо изменения. –

+1

@Mike: потому что 'os.walk' ссылается на исходный список, для того чтобы для понимания списка нужно было выполнить:' dirs [:] = [d для d в dirs, если не d.startswith ("keep _")] ' – SilentGhost

+0

О да, упс. Я уточню свой ответ. – FogleBird

Смежные вопросы