Я провел некоторое тестирование скорости для различных функций, чтобы вернуть полный путь ко всем текущим подкаталогам.
tl; dr:
всегда используйте scandir:
list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
Бонус: С помощью scandirвы также можете просто получать имена папок, используя f.nameвместо f.path.
Это (как и все другие функции ниже) не будет использовать естественную сортировку . Это означает, что результаты будут отсортированы следующим образом: 1, 10, 2. Чтобы получить естественную сортировку (1, 2, 10), просмотрите https://stackoverflow.com/a/48030307/2441026
Результаты :
scandiris: в 3 раза быстрее walk, в 32 раза быстрее listdir(с фильтром), в 35 раз быстрее Pathlibи в 36 раз быстрее listdirи в 37 раз (!) Быстрее, чем glob.
Протестировано с W7x64, Python 3.8.1. Папка с 440 подпапками.
В случае, если вам интересно, listdirможно ли ускорить работу, не выполняя os.path.join () дважды, да, но разница в принципе отсутствует.
Код:
import osimport pathlibimport timeitimport 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}")
Почему никто не упомянул glob? globпозволяет вам использовать расширение пути в стиле Unix, и это моя функция для работы почти со всем, что нужно для поиска более одного имени пути. Это делает это очень просто:
from glob import glob
paths = glob('*/')
Обратите внимание, что globвернет каталог с окончательной косой чертой (как и в случае с Unix), в то время как большинство pathоснованных решений пропустит последнюю косую черту.
Хорошее решение, простое и работает. Для тех, кто не хочет этот последний слэш, он может использовать это paths = [ p.replace('/', '') for p in glob('*/') ].
Эван Ху
5
Возможно, было бы безопаснее просто вырезать последний символ [p[:-1] for p in paths], так как этот метод замены также заменит любые экранированные косые черты в имени файла (не то, что они являются общими).
ари
3
Еще безопаснее использовать полоску ('/'), чтобы удалить косые черты. Этот способ гарантирует, что вы не будете вырезать символы, которые не являются косыми чертами
Eliezer Miron
8
По построению вы гарантированно получите косую черту (так что это не безопаснее), но я думаю, что она более читабельна. Вы определенно хотите использовать rstripвместо этого strip, так как последний превратит любые полностью определенные пути в относительные пути.
ари
7
дополнение к комментарию @ari для новичков в Python, таких как I: strip('/')удалит как начальный, так и конечный '/', rstrip('/')удалит только последний
Очень умный Хотя эффективность не имеет значения ( ... она полностью имеет значение ), мне любопытно, является ли это или глобальное выражение генератора (s.rstrip("/") for s in glob(parent_dir+"*/"))более эффективным по времени. Мое интуитивное подозрение заключается в том, что решение на stat()основе должно быть намного быстрее, чем глобализация в стиле оболочки. К сожалению, мне не хватает воли и на самом деле узнать. os.walk()timeit
Сесил Карри
3
Обратите внимание, что при этом возвращаются имена подкаталогов без префикса родительского каталога.
Павел Чернох
19
import os, os.path
Чтобы получить (полный путь) непосредственные подкаталоги в каталоге:
defSubDirPath(d):return filter(os.path.isdir,[os.path.join(d,f)for f in os.listdir(d)])
Чтобы получить самый последний (новейший) подкаталог:
walk () генерирует имена файлов в дереве каталогов, обходя дерево сверху вниз или снизу вверх. Для каждого каталога в дереве с корнем в вершине каталога (включая саму вершину) он выдает 3-кортеж (dirpath, dirnames, filenames).
Просто имейте в виду, что если вам нужны только подкаталоги первого уровня, то выходите из итерации os.walk после первого набора возвращаемых значений.
йойо
11
Этот метод прекрасно делает все это за один раз.
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
Так как некоторые комментаторы спрашивают, в чем преимущества использования библиотек Twisted для этого, я немного перейду к исходному вопросу.
Более конкретно в этом примере: в отличие от стандартной версии библиотеки, эта функция может быть реализована без импорта . Функция "subdirs" является полностью родовой в том смысле, что она работает только с аргументом. Для того чтобы копировать и перемещать файлы с использованием стандартной библиотеки, вам необходимо зависеть от open«встроенных listdir», возможно, « isdir» или « os.walk» или « shutil.copy». Может быть " os.path.join" тоже. Не говоря уже о том, что вам нужно, чтобы строка передавала аргумент для идентификации реального файла. Давайте посмотрим на полную реализацию, которая будет копировать «index.tpl» каждого каталога в «index.html»:
def copyTemplates(topdir):for subdir in subdirs(topdir):
tpl = subdir.child("index.tpl")if tpl.exists():
tpl.copyTo(subdir.child("index.html"))
Вышеуказанная функция «subdirs» может работать с любым FilePathобъектом. Что означает, среди прочего, ZipPathобъекты. К сожалению, ZipPathсейчас доступен только для чтения, но он может быть расширен для поддержки записи.
Вы также можете передать свои собственные объекты для тестирования. Для того чтобы протестировать предлагаемые здесь API-интерфейсы с использованием os.path, вы должны использовать импортированные имена и неявные зависимости и, как правило, выполнять черную магию, чтобы ваши тесты работали. С FilePath вы делаете что-то вроде этого:
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(...))
Поскольку я мало знаком с Twisted, я всегда рад дополнительной информации и примерам; этот ответ приятно видеть за это. Сказав это, поскольку этот подход требует значительно больше работы, чем использование встроенных модулей Python и установка Twisted, есть ли какие-либо преимущества в использовании этого, которые вы могли бы добавить к ответу?
Джаррет Харди
1
Ответ Глифа, вероятно, был вдохновлен тем фактом, что TwistedLore также использует файлы .tpl.
Константин
Ну, ясно, я не ожидаю, что испанская инквизиция :-) Я предположил, что "* .tpl" - это общая ссылка на некое абстрактное расширение, означающее "шаблон", а не конкретный шаблон Twisted (я видел .tpl, используемый во многих языки ведь). Хорошо знать.
Джаррет Харди
+1, следовательно, для перехода к возможному углу скручивания, хотя я все же хотел бы понять, что Twisted'd объект FilePath и функция walk () добавляют к стандартному API.
Джаррет Харди
Лично я нахожу, что «FilePath.walk () возвращает объекты пути» гораздо легче запомнить, чем «os.walk выдает 3 кортежа dir, dirs, files». Но есть и другие преимущества. FilePath допускает полиморфизм, что означает, что вы можете обходить вещи, отличные от файловых систем. Например, вы можете передать twisted.python.zippath.ZipArchive в мою функцию 'subdirs' и получить генератор ZipPath вместо FilePaths; ваша логика не меняется, но ваше приложение теперь волшебным образом обрабатывает zip-файлы. Если вы хотите проверить это, вам просто нужно предоставить объект, вам не нужно писать реальные файлы.
Символ
4
Я просто написал некоторый код для перемещения виртуальных машин vmware и в итоге использовал os.pathи shutilдля выполнения копирования файлов между подкаталогами.
-1: не сработает, так как shutil.copy будет копировать в текущий каталог, так что вам придется перезаписывать «index.html» в текущем каталоге один раз для каждого «index.tpl», найденного в дереве подкаталогов.
nosklo
1
Я должен упомянуть библиотеку path.py , которую я использую очень часто.
Извлечение непосредственных подкаталогов становится таким простым:
my_dir.dirs()
Полный рабочий пример:
from path importPath
my_directory =Path("path/to/my/directory")
subdirs = my_directory.dirs()
NB: my_directory все еще можно манипулировать как строку, так как Path является подклассом строки, но предоставляет кучу полезных методов для манипулирования путями
делаю хорошо, версия python 3.6, но мне нужно было стереть «self» из внутренних переменных функции
locometro
1
использовал внутри класса, обновили
Каниш Мэтью
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
child_dirsФункция принимает путь директории и возвращает список ближайших подкаталогов в нем.
dir
|-- dir_1
-- dir_2
child_dirs('dir')->['dir_1','dir_2']
Ответы:
Я провел некоторое тестирование скорости для различных функций, чтобы вернуть полный путь ко всем текущим подкаталогам.
tl; dr: всегда используйте
scandir
:list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
Бонус: С помощью
scandir
вы также можете просто получать имена папок, используяf.name
вместоf.path
.Это (как и все другие функции ниже) не будет использовать естественную сортировку . Это означает, что результаты будут отсортированы следующим образом: 1, 10, 2. Чтобы получить естественную сортировку (1, 2, 10), просмотрите https://stackoverflow.com/a/48030307/2441026
Результаты :
scandir
is: в 3 раза быстрееwalk
, в 32 раза быстрееlistdir
(с фильтром), в 35 раз быстрееPathlib
и в 36 раз быстрееlistdir
и в 37 раз (!) Быстрее, чемglob
.Протестировано с W7x64, Python 3.8.1. Папка с 440 подпапками.
В случае, если вам интересно,
listdir
можно ли ускорить работу, не выполняя os.path.join () дважды, да, но разница в принципе отсутствует.Код:
источник
источник
Почему никто не упомянул
glob
?glob
позволяет вам использовать расширение пути в стиле Unix, и это моя функция для работы почти со всем, что нужно для поиска более одного имени пути. Это делает это очень просто:Обратите внимание, что
glob
вернет каталог с окончательной косой чертой (как и в случае с Unix), в то время как большинствоpath
основанных решений пропустит последнюю косую черту.источник
paths = [ p.replace('/', '') for p in glob('*/') ]
.[p[:-1] for p in paths]
, так как этот метод замены также заменит любые экранированные косые черты в имени файла (не то, что они являются общими).rstrip
вместо этогоstrip
, так как последний превратит любые полностью определенные пути в относительные пути.strip('/')
удалит как начальный, так и конечный '/',rstrip('/')
удалит только последнийПроверьте « Получение списка всех подкаталогов в текущем каталоге ».
Вот версия Python 3:
источник
(s.rstrip("/") for s in glob(parent_dir+"*/"))
более эффективным по времени. Мое интуитивное подозрение заключается в том, что решение наstat()
основе должно быть намного быстрее, чем глобализация в стиле оболочки. К сожалению, мне не хватает воли и на самом деле узнать.os.walk()
timeit
Чтобы получить (полный путь) непосредственные подкаталоги в каталоге:
Чтобы получить самый последний (новейший) подкаталог:
источник
list( filter(...) )
.os.walk
твой друг в этой ситуации.Прямо из документации:
источник
Этот метод прекрасно делает все это за один раз.
источник
Использование Twisted модуля FilePath:
Так как некоторые комментаторы спрашивают, в чем преимущества использования библиотек Twisted для этого, я немного перейду к исходному вопросу.
В ветке есть улучшенная документация , объясняющая преимущества FilePath; Вы можете прочитать это.
Более конкретно в этом примере: в отличие от стандартной версии библиотеки, эта функция может быть реализована без импорта . Функция "subdirs" является полностью родовой в том смысле, что она работает только с аргументом. Для того чтобы копировать и перемещать файлы с использованием стандартной библиотеки, вам необходимо зависеть от
open
«встроенныхlistdir
», возможно, «isdir
» или «os.walk
» или «shutil.copy
». Может быть "os.path.join
" тоже. Не говоря уже о том, что вам нужно, чтобы строка передавала аргумент для идентификации реального файла. Давайте посмотрим на полную реализацию, которая будет копировать «index.tpl» каждого каталога в «index.html»:Вышеуказанная функция «subdirs» может работать с любым
FilePath
объектом. Что означает, среди прочего,ZipPath
объекты. К сожалению,ZipPath
сейчас доступен только для чтения, но он может быть расширен для поддержки записи.Вы также можете передать свои собственные объекты для тестирования. Для того чтобы протестировать предлагаемые здесь API-интерфейсы с использованием os.path, вы должны использовать импортированные имена и неявные зависимости и, как правило, выполнять черную магию, чтобы ваши тесты работали. С FilePath вы делаете что-то вроде этого:
источник
Я просто написал некоторый код для перемещения виртуальных машин vmware и в итоге использовал
os.path
иshutil
для выполнения копирования файлов между подкаталогами.Это не очень элегантно, но работает.
источник
Вот один из способов:
источник
Я должен упомянуть библиотеку path.py , которую я использую очень часто.
Извлечение непосредственных подкаталогов становится таким простым:
my_dir.dirs()
Полный рабочий пример:
источник
Следующая функция может быть вызвана как:
get_folders_in_directories_recursively (directory, index = 1) -> выдает список папок первого уровня
get_folders_in_directories_recursively (каталог) -> дает все подпапки
источник
child_dirs
Функция принимает путь директории и возвращает список ближайших подкаталогов в нем.источник
источник
Один лайнер, использующий pathlib:
источник