Como listar apenas diretórios de nível superior em Python?

132

Quero poder listar apenas os diretórios dentro de alguma pasta. Isso significa que eu não quero nomes de arquivos listados, nem subpastas adicionais.

Vamos ver se um exemplo ajuda. No diretório atual, temos:

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

No entanto, não quero nomes de arquivos listados. Também não quero subpastas como \ Lib \ curses. Essencialmente, o que eu quero funciona com o seguinte:

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

No entanto, estou me perguntando se existe uma maneira mais simples de obter os mesmos resultados. Tenho a impressão de que usar o os.walk apenas para retornar o nível superior é ineficiente / demais.

fuentesjr
fonte

Respostas:

125

Filtre o resultado usando os.path.isdir () (e use os.path.join () para obter o caminho real):

>>> [ 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
fonte
17
Isso exige muito processamento versus muito simples os.walk (). Next () [1]
Phyo Arkar Lwin
202

os.walk

Use os.walkcom a nextfunção item:

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

Para Python <= 2.5, use:

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

Como isso funciona

os.walké um gerador e a chamada nextobterá o primeiro resultado na forma de três tuplas (caminho de rota, nome de diretório, nome de arquivo). Assim, o [1]índice retorna apenas o dirnamesdessa tupla.

Alex Coventry
fonte
14
Um pouco mais de descrição sobre isso é que este é um gerador, ele não estará caminhando nos outros diretórios, a menos que você diga. Então .next () [1] faz em uma linha o que todas as compreensões da lista fazem. Eu provavelmente faria algo assim DIRNAMES=1e, em seguida, next()[DIRNAMES]para facilitar o entendimento para futuros mantenedores de código.
boatcoder
3
+1 solução incrível. Para especificar um diretório para navegar, use:os.walk( os.path.join(mypath,'.')).next()[1]
Daniel Reis
42
para python v3: next (os.walk ('.')) [1]
Andre Soares
se você vai fazer mais do que processamento de texto; ou seja, o processamento nas pastas reais então caminhos completos podem ser necessários:sorted( [os.path.join(os.getcwd(), item) for item in os.walk(os.curdir).next()[1]] )
DevPlayer
52

Filtre a lista usando os.path.isdir para detectar diretórios.

filter(os.path.isdir, os.listdir(os.getcwd()))
Colin Jensen
fonte
5
Penso que esta é de longe a melhor combinação de legibilidade e concisão em qualquer uma dessas respostas.
vergenzt
20
Isso não funcionou. Meu palpite é que os.listdirretorna um nome de arquivo / pasta, passado para os.path.isdir, mas o último precisa de um caminho completo.
Daniel Reis
3
filtro é mais rápido do que 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
fonte
4
Isto pode ser encurtado para filtro (os.path.isdir, os.listdir (os.getcwd ())
John Millikin
3
Alguém tem alguma informação sobre se a compreensão do filtro ou da lista é mais rápida? Caso contrário, é apenas um argumento subjetivo. Obviamente, isso pressupõe que há 10 milhões de diretórios no cwd e o desempenho é um problema.
Mark Roddy
12

Observe que, em vez de fazer os.listdir(os.getcwd()), é preferível fazer os.listdir(os.path.curdir). Menos uma chamada de função e é tão portátil.

Portanto, para concluir a resposta, obtenha uma lista de diretórios em uma pasta:

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

Se você preferir nomes de caminho completos, use esta função:

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
fonte
9

Isso parece funcionar também (pelo menos no linux):

import glob, os
glob.glob('*' + os.path.sep)
Travis
fonte
1
+1 para glob. Ele pode te salvar um monte de código, especialmente iterações, e é muito semelhante ao uso UNIX terminal ( ls)
Gerard
5
Em vez de glob.glob ('*' + os.path.sep), você pode escrever [dir para dir em glob.glob ("*") se os.path.isdir (dir)]
Eamonn MR
8

Apenas para acrescentar que o uso de os.listdir () não "exige muito processamento versus muito simples os.walk (). Next () [1]" . Isso ocorre porque o os.walk () usa os.listdir () internamente. De fato, se você testá-los juntos:

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

A filtragem de os.listdir () é muito ligeiramente mais rápida.

foz
fonte
2
Chegando em Python 3.5 é uma maneira mais rápida de obter o conteúdo do diretório: python.org/dev/peps/pep-0471
foz
1
pep-0471 - o scandirpacote - está disponível para o Python 2.6, como um pacote instalável no PyPI. Oferece substituições os.walke os.listdirque são muito mais rápidas.
foz
6

Uma maneira muito mais simples e elegante é usar isso:

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

Execute esse script na mesma pasta para a qual você deseja nomes de pastas. Ele fornecerá exatamente o nome imediato das pastas (isso também sem o caminho completo das pastas).

manty
fonte
6

Usando a compreensão da lista,

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

Eu acho que é a maneira mais simples

KBLee
fonte
2

sendo um novato aqui, ainda não posso comentar diretamente, mas aqui está uma pequena correção que gostaria de adicionar à parte seguinte do resposta ΤΖΩΤΖΙΟΥ :

Se você preferir nomes de caminho completos, use esta função:

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

para quem ainda está em python <2.4 : a construção interna precisa ser uma lista em vez de uma tupla e, portanto, deve ser assim:

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

caso contrário, obtém-se um erro de sintaxe.

antiplex
fonte
Eu sei que já faz um tempo, mas esse primeiro exemplo realmente me ajudou.
Inbar Rose
1
Você recebe um erro de sintaxe porque sua versão não suporta expressões de gerador. Eles foram introduzidos no Python 2.4, enquanto as compreensões de lista estão disponíveis desde o Python 2.0.
precisa saber é o seguinte
1
[x for x in os.listdir(somedir) if os.path.isdir(os.path.join(somedir, x))]
Moe
fonte
1

Para uma lista de nomes de caminhos completos, prefiro esta versão às outras soluções aqui:

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
fonte
1
scanDir = "abc"
directories = [d for d in os.listdir(scanDir) if os.path.isdir(os.path.join(os.path.abspath(scanDir), d))]
nvd
fonte
0

Uma opção mais segura que não falha quando não há diretório.

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
fonte
0

Igual a?

>>>> [path for path in os.listdir(os.getcwd()) if os.path.isdir(path)]
Kirk Strauser
fonte
0

O Python 3.4 introduziu o pathlibmódulo na biblioteca padrão, que fornece uma abordagem orientada a objetos para lidar com os caminhos do sistema de arquivos:

from pathlib import Path

p = Path('./')
[f for f in p.iterdir() if f.is_dir()]
joelostblom
fonte
-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
fonte