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.

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']

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.


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()))

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)]

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)
    ]

9

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

import glob, os
glob.glob('*' + os.path.sep)

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.


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).


6

Korzystanie ze zrozumienia list,

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

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


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.


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))]

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))]

1
scanDir = "abc"
directories = [d for d in os.listdir(scanDir) if os.path.isdir(os.path.join(os.path.abspath(scanDir), d))]

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 []


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()]

-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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.