Saya melakukan beberapa pengujian kecepatan pada berbagai fungsi untuk mengembalikan path lengkap ke semua subdirektori saat ini.
tl; dr:
Selalu gunakan scandir:
list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
Bonus: Dengan scandirAnda juga bisa hanya mendapatkan nama folder dengan menggunakan f.namebukan f.path.
Ini (serta semua fungsi lainnya di bawah) tidak akan menggunakan penyortiran alami . Ini berarti hasil akan diurutkan seperti ini: 1, 10, 2. Untuk mendapatkan penyortiran alami (1, 2, 10), silakan lihat di https://stackoverflow.com/a/48030307/2441026
Hasil :
scandiradalah: 3x lebih cepat dari walk, 32x lebih cepat dari listdir(dengan filter), 35x lebih cepat dari Pathlibdan 36x lebih cepat dari listdirdan 37x (!) Lebih cepat dari glob.
Diuji dengan W7x64, Python 3.8.1. Folder dengan 440 subfolder.
Jika Anda bertanya-tanya apakah listdirbisa dipercepat dengan tidak melakukan os.path.join () dua kali, ya, tetapi perbedaannya pada dasarnya tidak ada.
Kode:
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}")
Kenapa tidak ada yang menyebutkan glob? globmemungkinkan Anda menggunakan perluasan pathname gaya Unix, dan merupakan fungsi saya untuk hampir semua yang perlu menemukan lebih dari satu nama jalur. Itu membuatnya sangat mudah:
from glob import glob
paths = glob('*/')
Catatan yang globakan mengembalikan direktori dengan slash akhir (seperti yang akan unix) sementara sebagian besar pathsolusi berbasis akan menghilangkan slash akhir.
Solusi bagus, sederhana dan berhasil. Bagi mereka yang tidak menginginkan tebasan terakhir, dia bisa menggunakan ini paths = [ p.replace('/', '') for p in glob('*/') ].
Evan Hu
5
Mungkin lebih aman untuk hanya memotong karakter terakhir [p[:-1] for p in paths], karena metode ganti juga akan menggantikan setiap garis miring maju yang melarikan diri dalam nama file (bukan yang umum).
ari
3
Bahkan lebih aman, gunakan strip ('/') untuk menghapus garis miring. Dengan cara ini menjamin bahwa Anda tidak memotong karakter apa pun yang bukan garis miring
Eliezer Miron
8
Dengan konstruksi Anda dijamin memiliki garis miring (sehingga tidak lebih aman), tapi saya pikir itu lebih mudah dibaca. Anda pasti ingin menggunakan rstripbukan strip, karena yang terakhir akan mengubah jalur yang sepenuhnya memenuhi syarat menjadi jalur relatif.
ari
7
melengkapi komentar @ari untuk pemula python seperti I: strip('/')akan menghapus starting dan trailing '/', rstrip('/')hanya akan menghapus yang trailing
Sangat pintar. Sementara efisiensi tidak masalah ( ... benar-benar penting ), saya ingin tahu apakah ini atau ekspresi generator berbasis glob (s.rstrip("/") for s in glob(parent_dir+"*/"))lebih efisien waktu. Kecurigaan intuisi saya adalah bahwa solusi stat()berbasiskan seharusnya jauh lebih cepat daripada globbing gaya shell. Sayangnya, saya tidak memiliki kemauan untuk dan benar-benar mencari tahu. os.walk()timeit
Cecil Curry
3
Perhatikan bahwa ini mengembalikan nama subdirektori tanpa diawali nama direktori induk.
Paul Chernoch
19
import os, os.path
Untuk mendapatkan sub-direktori langsung (jalur penuh) langsung di direktori:
defSubDirPath(d):return filter(os.path.isdir,[os.path.join(d,f)for f in os.listdir(d)])
Untuk mendapatkan sub-direktori terbaru (terbaru):
walk () menghasilkan nama file di pohon direktori, dengan berjalan pohon itu dari atas ke bawah atau dari bawah ke atas. Untuk setiap direktori di pohon yang di-root di direktori teratas (termasuk top itu sendiri), ia menghasilkan 3-tuple (dirpath, dirnames, nama file).
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
Karena beberapa komentator telah bertanya apa keuntungan menggunakan perpustakaan Twisted untuk ini, saya akan sedikit melampaui pertanyaan aslinya di sini.
Lebih khusus dalam contoh ini: tidak seperti versi perpustakaan standar, fungsi ini dapat diimplementasikan tanpa impor . Fungsi "subdirs" sepenuhnya generik, dalam arti ia beroperasi hanya dengan argumennya. Untuk menyalin dan memindahkan file menggunakan pustaka standar, Anda harus bergantung pada " open" builtin, " listdir", mungkin " isdir" atau " os.walk" atau " shutil.copy". Mungkin " os.path.join" juga. Belum lagi fakta bahwa Anda perlu sebuah string melewati argumen untuk mengidentifikasi file yang sebenarnya. Mari kita lihat implementasi penuh yang akan menyalin "index.tpl" setiap direktori ke "index.html":
def copyTemplates(topdir):for subdir in subdirs(topdir):
tpl = subdir.child("index.tpl")if tpl.exists():
tpl.copyTo(subdir.child("index.html"))
Fungsi "subdirs" di atas dapat bekerja pada FilePathobjek seperti apa pun . Yang artinya, antara lain, ZipPathbenda. Sayangnya ZipPathhanya baca-sekarang, tetapi dapat diperluas untuk mendukung penulisan.
Anda juga dapat melewatkan objek Anda sendiri untuk tujuan pengujian. Untuk menguji API yang menggunakan os.path yang disarankan di sini, Anda harus menggunakan nama impor dan dependensi tersirat dan umumnya melakukan sihir hitam agar tes Anda berfungsi. Dengan FilePath, Anda melakukan sesuatu seperti ini:
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(...))
Karena saya memiliki sedikit paparan terhadap Twisted, saya selalu menyambut info dan contoh tambahan; jawaban ini bagus untuk dilihat. Karena itu, karena pendekatan ini tampaknya membutuhkan kerja lebih banyak daripada menggunakan modul python bawaan, dan instalasi Twisted, apakah ada keuntungan menggunakan ini yang dapat Anda tambahkan ke jawabannya?
Jarret Hardie
1
Jawaban Glyph mungkin terinspirasi oleh fakta bahwa TwistedLore juga menggunakan file .tpl.
Constantin
Yah, jelas saya tidak berharap inkuisisi Spanyol :-) Saya berasumsi "* .tpl" adalah referensi umum untuk beberapa ekstensi abstrak yang berarti "template", dan bukan template Twisted spesifik (saya telah melihat .tpl digunakan di banyak setelah semua bahasa). Senang mendengarnya.
Jarret Hardie
Karenanya, +1 untuk ranting ke sudut Twisted yang mungkin, meskipun saya masih ingin memahami apa yang ditambahkan objek 'FilePath' dan fungsi 'walk ()' ke API standar.
Jarret Hardie
Secara pribadi saya menemukan "FilePath.walk () menghasilkan objek path" jauh lebih mudah diingat daripada "os.walk menghasilkan 3-tupel dir, dirs, file". Namun ada manfaat lain. FilePath memungkinkan polimorfisme, yang berarti Anda dapat melintasi hal-hal selain sistem file. Sebagai contoh, Anda bisa memberikan twisted.python.zippath.ZipArchive ke fungsi 'subdirs' saya dan mendapatkan generator ZipPaths alih-alih FilePaths; logika Anda tidak berubah, tetapi aplikasi Anda sekarang secara ajaib menangani file zip. Jika Anda ingin mengujinya, Anda hanya perlu menyediakan objek, Anda tidak perlu menulis file nyata.
Glyph
4
Saya baru saja menulis beberapa kode untuk memindahkan mesin virtual vmware, dan akhirnya menggunakan os.pathdan shutilmenyelesaikan penyalinan file antara sub-direktori.
-1: tidak akan berfungsi, karena shutil.copy akan menyalin ke direktori saat ini, jadi Anda akan berakhir menimpa 'index.html' di direktori saat ini untuk setiap 'index.tpl' yang Anda temukan di pohon subdirektori.
nosklo
1
Saya harus menyebutkan perpustakaan path.py , yang sering saya gunakan.
Mengambil subdirektori langsung menjadi sesederhana itu:
my_dir.dirs()
Contoh kerja penuh adalah:
from path importPath
my_directory =Path("path/to/my/directory")
subdirs = my_directory.dirs()
NB: my_directory masih dapat dimanipulasi sebagai string, karena Path adalah subkelas string, tetapi menyediakan banyak metode yang berguna untuk memanipulasi jalur
baik, versi python 3.6, tapi saya harus menghapus "diri", dari variabel fungsi di dalam
locometro
1
sedang menggunakan di dalam kelas, telah diperbarui
Kanish Mathew
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
Itu child_dirs fungsi mengambil jalur direktori dan mengembalikan daftar subdirektori langsung di dalamnya.
dir
|-- dir_1
-- dir_2
child_dirs('dir')->['dir_1','dir_2']
Jawaban:
Saya melakukan beberapa pengujian kecepatan pada berbagai fungsi untuk mengembalikan path lengkap ke semua subdirektori saat ini.
tl; dr: Selalu gunakan
scandir
:list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
Bonus: Dengan
scandir
Anda juga bisa hanya mendapatkan nama folder dengan menggunakanf.name
bukanf.path
.Ini (serta semua fungsi lainnya di bawah) tidak akan menggunakan penyortiran alami . Ini berarti hasil akan diurutkan seperti ini: 1, 10, 2. Untuk mendapatkan penyortiran alami (1, 2, 10), silakan lihat di https://stackoverflow.com/a/48030307/2441026
Hasil :
scandir
adalah: 3x lebih cepat dariwalk
, 32x lebih cepat darilistdir
(dengan filter), 35x lebih cepat dariPathlib
dan 36x lebih cepat darilistdir
dan 37x (!) Lebih cepat dariglob
.Diuji dengan W7x64, Python 3.8.1. Folder dengan 440 subfolder.
Jika Anda bertanya-tanya apakah
listdir
bisa dipercepat dengan tidak melakukan os.path.join () dua kali, ya, tetapi perbedaannya pada dasarnya tidak ada.Kode:
sumber
sumber
Kenapa tidak ada yang menyebutkan
glob
?glob
memungkinkan Anda menggunakan perluasan pathname gaya Unix, dan merupakan fungsi saya untuk hampir semua yang perlu menemukan lebih dari satu nama jalur. Itu membuatnya sangat mudah:Catatan yang
glob
akan mengembalikan direktori dengan slash akhir (seperti yang akan unix) sementara sebagian besarpath
solusi berbasis akan menghilangkan slash akhir.sumber
paths = [ p.replace('/', '') for p in glob('*/') ]
.[p[:-1] for p in paths]
, karena metode ganti juga akan menggantikan setiap garis miring maju yang melarikan diri dalam nama file (bukan yang umum).rstrip
bukanstrip
, karena yang terakhir akan mengubah jalur yang sepenuhnya memenuhi syarat menjadi jalur relatif.strip('/')
akan menghapus starting dan trailing '/',rstrip('/')
hanya akan menghapus yang trailingCentang " Mendapatkan daftar semua subdirektori di direktori saat ini ".
Ini versi Python 3:
sumber
(s.rstrip("/") for s in glob(parent_dir+"*/"))
lebih efisien waktu. Kecurigaan intuisi saya adalah bahwa solusistat()
berbasiskan seharusnya jauh lebih cepat daripada globbing gaya shell. Sayangnya, saya tidak memiliki kemauan untuk dan benar-benar mencari tahu.os.walk()
timeit
Untuk mendapatkan sub-direktori langsung (jalur penuh) langsung di direktori:
Untuk mendapatkan sub-direktori terbaru (terbaru):
sumber
list( filter(...) )
.os.walk
adalah teman Anda dalam situasi ini.Langsung dari dokumentasi:
sumber
Metode ini dengan baik melakukan semuanya sekaligus.
sumber
Menggunakan modul FilePath Twisted:
Karena beberapa komentator telah bertanya apa keuntungan menggunakan perpustakaan Twisted untuk ini, saya akan sedikit melampaui pertanyaan aslinya di sini.
Ada beberapa dokumentasi yang ditingkatkan di cabang yang menjelaskan kelebihan FilePath; Anda mungkin ingin membacanya.
Lebih khusus dalam contoh ini: tidak seperti versi perpustakaan standar, fungsi ini dapat diimplementasikan tanpa impor . Fungsi "subdirs" sepenuhnya generik, dalam arti ia beroperasi hanya dengan argumennya. Untuk menyalin dan memindahkan file menggunakan pustaka standar, Anda harus bergantung pada "
open
" builtin, "listdir
", mungkin "isdir
" atau "os.walk
" atau "shutil.copy
". Mungkin "os.path.join
" juga. Belum lagi fakta bahwa Anda perlu sebuah string melewati argumen untuk mengidentifikasi file yang sebenarnya. Mari kita lihat implementasi penuh yang akan menyalin "index.tpl" setiap direktori ke "index.html":Fungsi "subdirs" di atas dapat bekerja pada
FilePath
objek seperti apa pun . Yang artinya, antara lain,ZipPath
benda. SayangnyaZipPath
hanya baca-sekarang, tetapi dapat diperluas untuk mendukung penulisan.Anda juga dapat melewatkan objek Anda sendiri untuk tujuan pengujian. Untuk menguji API yang menggunakan os.path yang disarankan di sini, Anda harus menggunakan nama impor dan dependensi tersirat dan umumnya melakukan sihir hitam agar tes Anda berfungsi. Dengan FilePath, Anda melakukan sesuatu seperti ini:
sumber
Saya baru saja menulis beberapa kode untuk memindahkan mesin virtual vmware, dan akhirnya menggunakan
os.path
danshutil
menyelesaikan penyalinan file antara sub-direktori.Itu tidak terlalu elegan, tetapi itu berhasil.
sumber
Ini salah satu caranya:
sumber
Saya harus menyebutkan perpustakaan path.py , yang sering saya gunakan.
Mengambil subdirektori langsung menjadi sesederhana itu:
my_dir.dirs()
Contoh kerja penuh adalah:
sumber
Fungsi berikut dapat disebut sebagai:
get_folders_in_directories_recursively (direktori, indeks = 1) -> memberikan daftar folder di tingkat pertama
get_folders_in_directories_recursively (direktori) -> memberikan semua sub folder
sumber
Itu
child_dirs
fungsi mengambil jalur direktori dan mengembalikan daftar subdirektori langsung di dalamnya.sumber
sumber
Satu liner menggunakan pathlib:
sumber