Fiz alguns testes de velocidade em várias funções para retornar o caminho completo para todos os subdiretórios atuais.
tl; dr:
Sempre use scandir:
list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
Bônus: Com scandirvocê, você também pode obter apenas nomes de pastas usando em f.namevez de f.path.
Isso (assim como todas as outras funções abaixo) não usará a classificação natural . Isso significa que os resultados serão classificados da seguinte forma: 1, 10, 2. Para obter a classificação natural (1, 2, 10), consulte https://stackoverflow.com/a/48030307/2441026
Resultados :
scandiré: 3x mais rápido que walk, 32x mais rápido que listdir(com filtro), 35x mais rápido que Pathlibe 36x mais rápido que listdire 37x (!) Mais rápido que glob.
Testado com W7x64, Python 3.8.1. Pasta com 440 subpastas.
Caso você se pergunte se listdirpoderia ser acelerado não executando os.path.join () duas vezes, sim, mas a diferença é basicamente inexistente.
Código:
import os
import pathlib
import timeit
import glob
path = r"<example_path>"def a():
list_subfolders_with_paths =[f.path for f in os.scandir(path)if f.is_dir()]# print(len(list_subfolders_with_paths))def b():
list_subfolders_with_paths =[os.path.join(path, f)for f in os.listdir(path)if os.path.isdir(os.path.join(path, f))]# print(len(list_subfolders_with_paths))def c():
list_subfolders_with_paths =[]for root, dirs, files in os.walk(path):for dir in dirs:
list_subfolders_with_paths.append( os.path.join(root, dir))break# print(len(list_subfolders_with_paths))def d():
list_subfolders_with_paths = glob.glob(path +'/*/')# print(len(list_subfolders_with_paths))def e():
list_subfolders_with_paths = list(filter(os.path.isdir,[os.path.join(path, f)for f in os.listdir(path)]))# print(len(list(list_subfolders_with_paths)))def f():
p = pathlib.Path(path)
list_subfolders_with_paths =[x for x in p.iterdir()if x.is_dir()]# print(len(list_subfolders_with_paths))print(f"Scandir: {timeit.timeit(a, number=1000):.3f}")print(f"Listdir: {timeit.timeit(b, number=1000):.3f}")print(f"Walk: {timeit.timeit(c, number=1000):.3f}")print(f"Glob: {timeit.timeit(d, number=1000):.3f}")print(f"Listdir (filter): {timeit.timeit(e, number=1000):.3f}")print(f"Pathlib: {timeit.timeit(f, number=1000):.3f}")
Por que ninguém mencionou glob? globpermite usar a expansão de nome de caminho no estilo Unix, e é minha função funcionar para quase tudo que precisa encontrar mais de um nome de caminho. Isso torna muito fácil:
from glob import glob
paths = glob('*/')
Observe que globretornará o diretório com a barra final (como o unix faria), enquanto a maioria das pathsoluções baseadas omitirá a barra final.
Boa solução, simples e funciona. Para quem não quer a barra final, ele pode usar isso paths = [ p.replace('/', '') for p in glob('*/') ].
Evan Hu
5
Pode ser mais seguro simplesmente cortar o último caractere [p[:-1] for p in paths], pois esse método de substituição também substituirá as barras invertidas escapadas no nome do arquivo (não que sejam comuns).
Ari
3
Ainda mais seguro, use a tira ('/') para remover as barras finais. Desta forma, garante que você não cortar qualquer caracteres que não são barras
Eliezer Miron
8
Por construção, você tem a garantia de ter uma barra final (por isso não é mais seguro), mas acho que é mais legível. Você definitivamente deseja usar, em rstripvez de strip, já que o último transformará todos os caminhos totalmente qualificados em caminhos relativos.
ari
7
complemento ao comentário @ari para iniciantes em python, como I: strip('/')removerá o inicial e o final '/', rstrip('/')removerá apenas o final
Extremamente inteligente. Embora a eficiência não importe ( ... totalmente ), estou curioso para saber se essa ou a expressão do gerador baseado em glob (s.rstrip("/") for s in glob(parent_dir+"*/"))é mais eficiente em termos de tempo. Minha suspeita intuitiva é que uma solução stat()baseada em deve ser profundamente mais rápida do que o globbing do tipo shell. Infelizmente, eu não tenho vontade e realmente descubro. os.walk()timeit
Cecil Curry
3
Observe que isso retorna os nomes dos subdiretórios sem o nome do diretório pai prefixado.
Paul Chernoch 11/08/19
19
import os, os.path
Para obter subdiretórios imediatos (caminho completo) em um diretório:
defSubDirPath(d):return filter(os.path.isdir,[os.path.join(d,f)for f in os.listdir(d)])
Para obter o subdiretório mais recente (mais recente):
walk () gera os nomes de arquivo em uma árvore de diretórios, percorrendo a árvore de cima para baixo ou de baixo para cima. Para cada diretório na árvore enraizado no topo do diretório (incluindo o próprio topo), ele gera três tuplas (caminho de rota, nome de diretório, nome de arquivo).
Lembre-se de que se você deseja apenas os subdiretórios de primeiro nível, interrompa a iteração os.walk após o primeiro conjunto de valores de retorno.
yoyo
11
Este método faz tudo de uma só vez.
from glob import glob
subd =[s.rstrip("/")for s in glob(parent_dir+"*/")]
from twisted.python.filepath importFilePathdef subdirs(pathObj):for subpath in pathObj.walk():if subpath.isdir():yield subpath
if __name__ =='__main__':for subdir in subdirs(FilePath(".")):print"Subdirectory:", subdir
Como alguns comentaristas perguntaram quais são as vantagens de usar as bibliotecas do Twisted, vou além da pergunta original aqui.
Mais especificamente neste exemplo: diferente da versão da biblioteca padrão, esta função pode ser implementada sem importações . A função "subdireta" é totalmente genérica, pois opera apenas com base em seu argumento. Para copiar e mover os arquivos usando a biblioteca padrão, você precisa depender do " open" builtin " listdir" ", talvez" isdir"ou" os.walk"ou" shutil.copy". Talvez " os.path.join" também. Sem mencionar o fato de que você precisa de uma sequência passada em um argumento para identificar o arquivo real. Vamos dar uma olhada na implementação completa que copiará o "index.tpl" de cada diretório para "index.html":
def copyTemplates(topdir):for subdir in subdirs(topdir):
tpl = subdir.child("index.tpl")if tpl.exists():
tpl.copyTo(subdir.child("index.html"))
A função "subdirs" acima pode funcionar em qualquer FilePathobjeto semelhante. O que significa, entre outras coisas, ZipPathobjetos. Infelizmente, agora ZipPathé somente leitura, mas pode ser estendido para oferecer suporte à gravação.
Você também pode passar seus próprios objetos para fins de teste. Para testar as APIs de uso do os.path sugeridas aqui, você precisa usar nomes importados e dependências implícitas e geralmente executar magia negra para que seus testes funcionem. Com o FilePath, você faz algo assim:
classMyFakePath:def child(self, name):"Return an appropriate child object"def walk(self):"Return an iterable of MyFakePath objects"def exists(self):"Return true or false, as appropriate to the test"def isdir(self):"Return true or false, as appropriate to the test"...
subdirs(MyFakePath(...))
Como tenho pouca exposição ao Twisted, sempre recebo informações e exemplos adicionais; é bom ver essa resposta para isso. Dito isto, uma vez que essa abordagem parece exigir substancialmente mais trabalho do que usar os módulos python internos e uma instalação Twisted, existem vantagens em usar isso que você possa adicionar à resposta?
Jarret Hardie
1
A resposta de Glyph provavelmente foi inspirada pelo fato de o TwistedLore também usar arquivos .tpl.
Constantin
Bem, claramente não espero que a inquisição em espanhol :-) Presumi que "* .tpl" fosse uma referência genérica a alguma extensão abstrata que significa "modelo", e não um modelo Twisted específico (eu já vi .tpl usado em muitos afinal de contas). Bom saber.
Jarret Hardie
+1, portanto, para alternar para o possível ângulo torcido, embora eu ainda queira entender o que o objeto 'FilePath' do Twisted e a função 'walk ()' adicionam à API padrão.
Jarret Hardie
Pessoalmente, acho que "FilePath.walk () produz objetos de caminho" muito mais fácil de lembrar do que "os.walk produz 3 tuplas de diretórios, diretórios, arquivos". Mas há outros benefícios. O FilePath permite polimorfismo, o que significa que você pode percorrer outras coisas além dos sistemas de arquivos. Por exemplo, você pode passar um twisted.python.zippath.ZipArchive para a função 'subdirs' e obter um gerador de ZipPaths em vez de FilePaths; sua lógica não muda, mas seu aplicativo agora lida magicamente com arquivos zip. Se quiser testá-lo, basta fornecer um objeto, não é necessário gravar arquivos reais.
Glyph
4
Acabei de escrever um código para mover as máquinas virtuais vmware e acabei usando os.path e shutilrealizando a cópia de arquivos entre subdiretórios.
-1: não funcionará, já que shutil.copy será copiado para o diretório atual, então você substituirá 'index.html' no diretório atual uma vez para cada 'index.tpl' encontrado na árvore de subdiretórios.
Nosklo 29/04/09
1
Eu tenho que mencionar o path.py biblioteca , que eu uso com muita frequência.
A busca dos subdiretórios imediatos se torna tão simples quanto isso:
my_dir.dirs()
O exemplo completo de trabalho é:
from path importPath
my_directory =Path("path/to/my/directory")
subdirs = my_directory.dirs()
NB: my_directory ainda pode ser manipulado como uma string, já que Path é uma subclasse de string, mas fornece vários métodos úteis para manipular caminhos
fazendo bom, versão python 3.6, mas eu precisava apagar "self", de dentro das variáveis de função
locometro 25/06
1
estava usando dentro de uma classe, atualizei
Kanish Mathew 25/06
0
import glob
import os
def child_dirs(path):
cd = os.getcwd()# save the current working directory
os.chdir(path)# change directory
dirs = glob.glob("*/")# get all the subdirectories
os.chdir(cd)# change directory to the script original locationreturn dirs
A child_dirsfunção pega um caminho de diretório e retorna uma lista dos subdiretórios imediatos nele.
dir
|-- dir_1
-- dir_2
child_dirs('dir')->['dir_1','dir_2']
Respostas:
Fiz alguns testes de velocidade em várias funções para retornar o caminho completo para todos os subdiretórios atuais.
tl; dr: Sempre use
scandir
:list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
Bônus: Com
scandir
você, você também pode obter apenas nomes de pastas usando emf.name
vez def.path
.Isso (assim como todas as outras funções abaixo) não usará a classificação natural . Isso significa que os resultados serão classificados da seguinte forma: 1, 10, 2. Para obter a classificação natural (1, 2, 10), consulte https://stackoverflow.com/a/48030307/2441026
Resultados :
scandir
é: 3x mais rápido quewalk
, 32x mais rápido quelistdir
(com filtro), 35x mais rápido quePathlib
e 36x mais rápido quelistdir
e 37x (!) Mais rápido queglob
.Testado com W7x64, Python 3.8.1. Pasta com 440 subpastas.
Caso você se pergunte se
listdir
poderia ser acelerado não executando os.path.join () duas vezes, sim, mas a diferença é basicamente inexistente.Código:
fonte
fonte
Por que ninguém mencionou
glob
?glob
permite usar a expansão de nome de caminho no estilo Unix, e é minha função funcionar para quase tudo que precisa encontrar mais de um nome de caminho. Isso torna muito fácil:Observe que
glob
retornará o diretório com a barra final (como o unix faria), enquanto a maioria daspath
soluções baseadas omitirá a barra final.fonte
paths = [ p.replace('/', '') for p in glob('*/') ]
.[p[:-1] for p in paths]
, pois esse método de substituição também substituirá as barras invertidas escapadas no nome do arquivo (não que sejam comuns).rstrip
vez destrip
, já que o último transformará todos os caminhos totalmente qualificados em caminhos relativos.strip('/')
removerá o inicial e o final '/',rstrip('/')
removerá apenas o finalMarque " Obtendo uma lista de todos os subdiretórios no diretório atual ".
Aqui está uma versão do Python 3:
fonte
(s.rstrip("/") for s in glob(parent_dir+"*/"))
é mais eficiente em termos de tempo. Minha suspeita intuitiva é que uma soluçãostat()
baseada em deve ser profundamente mais rápida do que o globbing do tipo shell. Infelizmente, eu não tenho vontade e realmente descubro.os.walk()
timeit
Para obter subdiretórios imediatos (caminho completo) em um diretório:
Para obter o subdiretório mais recente (mais recente):
fonte
list( filter(...) )
.os.walk
é seu amigo nesta situação.Diretamente da documentação:
fonte
Este método faz tudo de uma só vez.
fonte
Usando o módulo FilePath do Twisted:
Como alguns comentaristas perguntaram quais são as vantagens de usar as bibliotecas do Twisted, vou além da pergunta original aqui.
Há alguma documentação aprimorada em uma ramificação que explica as vantagens do FilePath; você pode querer ler isso.
Mais especificamente neste exemplo: diferente da versão da biblioteca padrão, esta função pode ser implementada sem importações . A função "subdireta" é totalmente genérica, pois opera apenas com base em seu argumento. Para copiar e mover os arquivos usando a biblioteca padrão, você precisa depender do "
open
" builtin "listdir
" ", talvez"isdir
"ou"os.walk
"ou"shutil.copy
". Talvez "os.path.join
" também. Sem mencionar o fato de que você precisa de uma sequência passada em um argumento para identificar o arquivo real. Vamos dar uma olhada na implementação completa que copiará o "index.tpl" de cada diretório para "index.html":A função "subdirs" acima pode funcionar em qualquer
FilePath
objeto semelhante. O que significa, entre outras coisas,ZipPath
objetos. Infelizmente, agoraZipPath
é somente leitura, mas pode ser estendido para oferecer suporte à gravação.Você também pode passar seus próprios objetos para fins de teste. Para testar as APIs de uso do os.path sugeridas aqui, você precisa usar nomes importados e dependências implícitas e geralmente executar magia negra para que seus testes funcionem. Com o FilePath, você faz algo assim:
fonte
Acabei de escrever um código para mover as máquinas virtuais vmware e acabei usando
os.path
eshutil
realizando a cópia de arquivos entre subdiretórios.Não é muito elegante, mas funciona.
fonte
Aqui está uma maneira:
fonte
Eu tenho que mencionar o path.py biblioteca , que eu uso com muita frequência.
A busca dos subdiretórios imediatos se torna tão simples quanto isso:
my_dir.dirs()
O exemplo completo de trabalho é:
fonte
A seguinte função pode ser chamada como:
get_folders_in_directories_recursively (diretório, índice = 1) -> fornece a lista de pastas no primeiro nível
get_folders_in_directories_recursively (directory) -> fornece todas as subpastas
fonte
A
child_dirs
função pega um caminho de diretório e retorna uma lista dos subdiretórios imediatos nele.fonte
fonte
Um liner usando pathlib:
fonte