Jak wyświetlić tylko katalogi najwyższego poziomu w Pythonie?

132

Chcę mieć możliwość wyświetlenia tylko katalogów znajdujących się w jakimś folderze. Oznacza to, że nie chcę, aby nazwy plików były wyświetlane, ani nie chcę dodatkowych podfolderów.

Zobaczmy, czy przykład pomoże. W aktualnym katalogu mamy:

>>> os.listdir(os.getcwd())
['cx_Oracle-doc', 'DLLs', 'Doc', 'include', 'Lib', 'libs', 'LICENSE.txt', 'mod_p
ython-wininst.log', 'NEWS.txt', 'pymssql-wininst.log', 'python.exe', 'pythonw.ex
e', 'README.txt', 'Removemod_python.exe', 'Removepymssql.exe', 'Scripts', 'tcl',
 'Tools', 'w9xpopen.exe']

Jednak nie chcę, aby nazwy plików były wymienione. Nie chcę też podfolderów, takich jak \ Lib \ curses. Zasadniczo to, czego chcę, działa z następującymi:

>>> for root, dirnames, filenames in os.walk('.'):
...     print dirnames
...     break
...
['cx_Oracle-doc', 'DLLs', 'Doc', 'include', 'Lib', 'libs', 'Scripts', 'tcl', 'Tools']

Zastanawiam się jednak, czy istnieje prostszy sposób na osiągnięcie takich samych wyników. Mam wrażenie, że używanie os.walk tylko do powrotu do najwyższego poziomu jest nieefektywne / zbyt duże.

fuentesjr
źródło

Odpowiedzi:

125

Przefiltruj wynik za pomocą os.path.isdir () (i użyj os.path.join (), aby uzyskać prawdziwą ścieżkę):

>>> [ name for name in os.listdir(thedir) if os.path.isdir(os.path.join(thedir, name)) ]
['ctypes', 'distutils', 'encodings', 'lib-tk', 'config', 'idlelib', 'xml', 'bsddb', 'hotshot', 'logging', 'doc', 'test', 'compiler', 'curses', 'site-packages', 'email', 'sqlite3', 'lib-dynload', 'wsgiref', 'plat-linux2', 'plat-mac']
Thomas Wouters
źródło
17
To wymaga dużo przetwarzania w porównaniu z bardzo prostym os.walk (). Next () [1]
Phyo Arkar Lwin
203

os.walk

Użyj os.walkz nextfunkcją przedmiotu:

next(os.walk('.'))[1]

W przypadku Pythona <= 2.5 użyj:

os.walk('.').next()[1]

Jak to działa

os.walkjest generatorem i wywołanie nextotrzyma pierwszy wynik w postaci 3-krotek (dirpath, dirnames, filenames). Dlatego [1]indeks zwraca tylko dirnamesz tej krotki.

Alex Coventry
źródło
14
Trochę więcej opisu na ten temat jest takie, że to jest generator, nie będzie chodził po innych reżach, chyba że mu powiesz. Zatem .next () [1] robi w jednym wierszu to samo, co wszystkie wyrażenia listowe. Prawdopodobnie zrobiłbym coś takiego, DIRNAMES=1a potem next()[DIRNAMES]ułatwiłbym zrozumienie przyszłym opiekunom kodu.
boatcoder
3
+1 niesamowite rozwiązanie. Aby określić katalog do przeglądania, użyj:os.walk( os.path.join(mypath,'.')).next()[1]
Daniel Reis
42
for python v3: next (os.walk ('.')) [1]
Andre Soares
jeśli zamierzasz zrobić więcej niż przetwarzanie tekstu; tj. przetwarzanie w rzeczywistych folderach, wtedy mogą być potrzebne pełne ścieżki:sorted( [os.path.join(os.getcwd(), item) for item in os.walk(os.curdir).next()[1]] )
DevPlayer
52

Przefiltruj listę za pomocą os.path.isdir, aby wykryć katalogi.

filter(os.path.isdir, os.listdir(os.getcwd()))
Colin Jensen
źródło
5
Myślę, że jest to zdecydowanie najlepsza kombinacja czytelności i zwięzłości w każdej z tych odpowiedzi.
vergenzt
20
To nie zadziałało. Domyślam się, że os.listdirzwraca nazwę pliku / folderu, przekazaną do os.path.isdir, ale ta ostatnia wymaga pełnej ścieżki.
Daniel Reis
3
filtr jest szybszy niż os.walk timeit(os.walk(os.getcwd()).next()[1]) 1000 loops, best of 3: 734 µs per loop timeit(filter(os.path.isdir, os.listdir(os.getcwd()))) 1000 loops, best of 3: 477 µs per loop
B.Kocis
14
directories=[d for d in os.listdir(os.getcwd()) if os.path.isdir(d)]
Mark Roddy
źródło
4
Można to skrócić do filtra (os.path.isdir, os.listdir (os.getcwd ())
John Millikin
3
Czy ktoś ma jakieś informacje o tym, czy filtr lub lista jest szybsza? W przeciwnym razie jest to tylko subiektywny argument. To oczywiście zakłada, że ​​w cwd jest 10 milionów katalogów, a wydajność jest problemem.
Mark Roddy,
12

Zauważ, że zamiast robić os.listdir(os.getcwd()), lepiej to zrobić os.listdir(os.path.curdir). Jedno wywołanie funkcji mniej i jest równie przenośne.

Tak więc, aby uzupełnić odpowiedź, aby uzyskać listę katalogów w folderze:

def listdirs(folder):
    return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]

Jeśli wolisz pełne nazwy ścieżek, użyj tej funkcji:

def listdirs(folder):
    return [
        d for d in (os.path.join(folder, d1) for d1 in os.listdir(folder))
        if os.path.isdir(d)
    ]
tzot
źródło
9

Wydaje się, że to też działa (przynajmniej na Linuksie):

import glob, os
glob.glob('*' + os.path.sep)
Travis
źródło
1
+1 dla glob. Pozwala zaoszczędzić sporo kodu, zwłaszcza iteracji, i jest bardzo podobny do użycia terminala UNIX ( ls)
Gerard
5
Zamiast glob.glob ('*' + os.path.sep) możesz napisać [dir for dir in glob.glob ("*") if os.path.isdir (dir)]
Eamonn MR
8

Wystarczy dodać, że użycie os.listdir () nie "wymaga dużo przetwarzania w porównaniu z bardzo prostym os.walk (). Next () [1]" . Dzieje się tak, ponieważ os.walk () używa wewnętrznie os.listdir (). W rzeczywistości, jeśli przetestujesz je razem:

>>>> import timeit
>>>> timeit.timeit("os.walk('.').next()[1]", "import os", number=10000)
1.1215229034423828
>>>> timeit.timeit("[ name for name in os.listdir('.') if os.path.isdir(os.path.join('.', name)) ]", "import os", number=10000)
1.0592019557952881

Filtrowanie os.listdir () jest bardzo nieznacznie szybsze.

foz
źródło
2
Jadąc w Pythonie 3.5 jest szybszy sposób na uzyskanie zawartości katalogu: python.org/dev/peps/pep-0471
Foz
1
pep-0471 - scandirpakiet - jest szczęśliwie dostępny od Pythona 2.6 jako pakiet instalowalny na PyPI. Oferuje zamienniki os.walki os.listdirsą znacznie szybsze.
foz
6

O wiele prostszym i bardziej eleganckim sposobem jest użycie tego:

 import os
 dir_list = os.walk('.').next()[1]
 print dir_list

Uruchom ten skrypt w tym samym folderze, dla którego chcesz uzyskać nazwy folderów, poda ci dokładnie tylko nazwy bezpośrednich folderów (bez pełnej ścieżki do folderów).

manty
źródło
6

Korzystanie ze zrozumienia list,

[a for a in os.listdir() if os.path.isdir(a)]

Myślę, że to najprostszy sposób

KBLee
źródło
2

będąc tu nowicjuszem, nie mogę jeszcze bezpośrednio komentować, ale oto mała poprawka, którą chciałbym dodać do następującej części odpowiedzi ΤΖΩΤΖΙΟΥ :

Jeśli wolisz pełne nazwy ścieżek, użyj tej funkcji:

def listdirs(folder):  
  return [
    d for d in (os.path.join(folder, d1) for d1 in os.listdir(folder))
    if os.path.isdir(d)
]

dla tych, którzy nadal korzystają z Pythona <2.4 : konstrukcja wewnętrzna musi być listą zamiast krotką i dlatego powinna wyglądać następująco:

def listdirs(folder):  
  return [
    d for d in [os.path.join(folder, d1) for d1 in os.listdir(folder)]
    if os.path.isdir(d)
  ]

w przeciwnym razie pojawia się błąd składniowy.

antypleks
źródło
wiem, że minęło trochę czasu, ale ten pierwszy przykład naprawdę mi pomógł.
Inbar Rose
1
Pojawia się błąd składni, ponieważ Twoja wersja nie obsługuje wyrażeń generatora. Zostały one wprowadzone w Pythonie 2.4, podczas gdy listy składane były dostępne od Pythona 2.0.
awatts
1
[x for x in os.listdir(somedir) if os.path.isdir(os.path.join(somedir, x))]
Moe
źródło
1

Aby uzyskać listę pełnych nazw ścieżek, wolę tę wersję od innych rozwiązań tutaj:

def listdirs(dir):
    return [os.path.join(os.path.join(dir, x)) for x in os.listdir(dir) 
        if os.path.isdir(os.path.join(dir, x))]
Malius Arth
źródło
1
scanDir = "abc"
directories = [d for d in os.listdir(scanDir) if os.path.isdir(os.path.join(os.path.abspath(scanDir), d))]
nvd
źródło
0

Bezpieczniejsza opcja, która nie zawiedzie, gdy nie ma katalogu.

def listdirs(folder):
    if os.path.exists(folder):
         return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]
    else:
         return []
Alexey Gavrilov
źródło
0

Tak jak to?

>>>> [path for path in os.listdir(os.getcwd()) if os.path.isdir(path)]
Kirk Strauser
źródło
0

Python 3.4 wprowadziła ten pathlibmoduł do standardowej biblioteki, która zapewnia podejścia obiektowego do ścieżek uchwyt systemu plików:

from pathlib import Path

p = Path('./')
[f for f in p.iterdir() if f.is_dir()]
joelostblom
źródło
-1
-- This will exclude files and traverse through 1 level of sub folders in the root

def list_files(dir):
    List = []
    filterstr = ' '
    for root, dirs, files in os.walk(dir, topdown = True):
        #r.append(root)
        if (root == dir):
            pass
        elif filterstr in root:
            #filterstr = ' '
            pass
        else:
            filterstr = root
            #print(root)
            for name in files:
                print(root)
                print(dirs)
                List.append(os.path.join(root,name))
            #print(os.path.join(root,name),"\n")
                print(List,"\n")

    return List
venkata maddineni
źródło