Seite 1 von 1

Verzeichnis liste ohne versteckte Verzeichnisse...

Verfasst: Montag 14. Juli 2008, 14:16
von jens
Stehe gerade auf den Schlauch... Ich möchte eine Liste aller Verzeichnisse und Unterverzeichnisse, aber ohne versteckte Verzeichnisse... Also alle Pfade die mit Punkt anfangen auslassen...

Mit os.walk() kommt man da nicht so schnell weiter...

Idee?

Rekursive Funktion mit os.listdir() ?

EDIT: Hm:

Code: Alles auswählen

import os, dircache

media_root = "./media"

def dir_walk(path):
    for name in dircache.listdir(path):
        if name.startswith("."):
            continue

        abs_path = os.path.join(path, name)
        if not os.path.isdir(abs_path):
            continue

        yield abs_path

        for dir in dir_walk(abs_path):
            yield dir


for i in dir_walk(media_root):
   print i
Was haltet ihr davon?

Verfasst: Montag 14. Juli 2008, 14:32
von audax

Code: Alles auswählen

import os

found = []
for root, dirs, files in os.walk('blub'):
    found.extend(d for d in dirs if not d.startswith('.'))

print found

Verfasst: Montag 14. Juli 2008, 14:35
von jens
Ne, ich brauche den vollen Pfad...

Verfasst: Montag 14. Juli 2008, 14:36
von audax

Code: Alles auswählen

import os

found = []
for root, dirs, files in os.walk('blub'):
    found.extend(os.path.join(root, d) for d in dirs if not d.startswith('.'))

print found 
Muss man dir denn alles vorkauen? :D

Verfasst: Montag 14. Juli 2008, 14:38
von jens
Selbst mal ausprobiert? So einfach ist das nicht...

Sowas kommt raus:

Code: Alles auswählen

./media/PyLucid
./media/.svn/tmp
./media/.svn/props
./media/.svn/prop-base
./media/.svn/text-base
./media/.svn/tmp/props
./media/.svn/tmp/prop-base
./media/.svn/tmp/text-base
./media/PyLucid/tiny_mce
./media/PyLucid/internal_page
...
Das Verzeichnis ./media/.svn wird zwar ausgelassen, aber nicht die Unterverzeichnis darin ;)

Verfasst: Montag 14. Juli 2008, 14:48
von audax

Code: Alles auswählen

import os

found = []
for root, dirs, files in os.walk('blub'):
    for d in dirs:
        if d.startswith('.'):
            dirs.remove(d)
    found.extend(os.path.join(root, d) for d in dirs)

print found
Dann entfernt man die eben :D

Verfasst: Montag 14. Juli 2008, 15:00
von jens
Ne, ich glaube os.walk() ist hier nicht angebracht. Es ist langsamer, wenn auch nicht viel:

Code: Alles auswählen

import timeit, os

def dir_walk1(path):
    result = []
    for name in os.listdir(path):
        if name.startswith("."):
            continue

        abs_path = os.path.join(path, name)
        if not os.path.isdir(abs_path):
            continue

        result.append(abs_path)
        sub_dirs = dir_walk1(abs_path)
        if sub_dirs:
            result += sub_dirs

    return result

#_____________________________________________________________________________

def dir_walk2(path):
    found = []
    for root, dirs, files in os.walk(path):
        for d in dirs:
            if d.startswith('.'):
                dirs.remove(d)
        found.extend(os.path.join(root, d) for d in dirs)
    return found

#_____________________________________________________________________________

def dir_walk3(path):
    found = []
    for root, dirs, files in os.walk(path):
        for d in dirs:
            if d.startswith('.'):
                dirs.remove(d)
            else:
                found.append(os.path.join(root, d))

    return found

#_____________________________________________________________________________


loop = 20

tests = (
    ("dir_walk1('.')", "from __main__ import os, dir_walk1"),
    ("dir_walk2('.')", "from __main__ import os, dir_walk2"),
    ("dir_walk3('.')", "from __main__ import os, dir_walk3"),
)

for no, test in enumerate(tests):
    print "%s - %s" % (no+1, test[0])

    test = timeit.Timer(test[0], test[1])
    print "%.2f" % test.timeit(number=loop)

    print
Ausgabe:
1 - dir_walk1('.')
0.79

2 - dir_walk2('.')
1.06

3 - dir_walk3('.')
0.97
@audax: dir_walk2() ist deine Variante...

Verfasst: Montag 14. Juli 2008, 15:05
von audax
achso, es geht um jeden Zyklus, das wusste ich nicht!

Ich dachte schon, es geht um Lesbarkeit und Wartbarkeit...wie bin ich blos darauf gekommen...

Verfasst: Montag 14. Juli 2008, 15:13
von noob1
in der eingesparten zeit könnte er die welt retten...

Verfasst: Montag 14. Juli 2008, 15:14
von jens
Meine Variante kann man noch vereinfachen, denn ich if Abfrage kann man sich sparen.
externd ist wohl auch schneller als ein +=
Statt os.listdir nutzte ich auch eigentlich dircache.listdir, was nochmal ein tick schneller ist ;)

Ich nutzte dir_walk2():

Code: Alles auswählen

import timeit, os, dircache

def dir_walk1(path):
    result = []
    for name in os.listdir(path):
        if name.startswith("."):
            continue

        abs_path = os.path.join(path, name)
        if not os.path.isdir(abs_path):
            continue

        result.append(abs_path)
        result.extend(dir_walk1(abs_path))

    return result

#_____________________________________________________________________________

def dir_walk2(path):
    result = []
    for name in dircache.listdir(path):
        if name.startswith("."):
            continue

        abs_path = os.path.join(path, name)
        if not os.path.isdir(abs_path):
            continue

        result.append(abs_path)
        result.extend(dir_walk1(abs_path))

    return result

#_____________________________________________________________________________

def dir_walk3(path):
    found = []
    for root, dirs, files in os.walk(path):
        for d in dirs:
            if d.startswith('.'):
                dirs.remove(d)
            else:
                found.append(os.path.join(root, d))

    return found

#_____________________________________________________________________________


loop = 100

tests = (
    ("dir_walk1('.')", "from __main__ import os, dir_walk1"),
    ("dir_walk2('.')", "from __main__ import os, dircache, dir_walk2"),
    ("dir_walk3('.')", "from __main__ import os, dir_walk3"),
)

for no, test in enumerate(tests):
    print "%s - %s" % (no+1, test[0])

    test = timeit.Timer(test[0], test[1])
    print "%.2f" % test.timeit(number=loop)

    print
Ergebnis:

Code: Alles auswählen

1 - dir_walk1('.')
4.10

2 - dir_walk2('.')
3.75

3 - dir_walk3('.')
5.07
Finde jetzt nicht, das dir_walk2() wesentlich undurchsichtiger wäre als dir_walk3()...

Später kommt evtl. noch eine "skip-Liste" hinzu...

Verfasst: Montag 14. Juli 2008, 15:16
von audax
Naja, für mich fällt das unter "unnötige Mikrooptimierung".

Verfasst: Montag 14. Juli 2008, 15:19
von BlackJack
Oh bitte Leute, ihr programmiert doch nicht erst seit gestern in Python: Aus einer Liste Elemente entfernen während man darüber iteriert ist eine doofe Idee. Also bitte die ``for``-Schleife durch so etwas hier ersetzen:

Code: Alles auswählen

dirs[:] = [d for d if d[0] != '.']

Verfasst: Montag 14. Juli 2008, 15:23
von audax
uhm...da war ja was...

Verfasst: Montag 14. Juli 2008, 16:40
von BlackJack
@jens: Vielleicht ist die `os.walk()` Lösung ja auch deswegen geringfügig langsamer, weil bei aufeinander folgenden versteckten Verzeichnissen jedes zweite doch im Ergebnis landet, wenn man ``for`` und `remove()` verwendet.