मैं एक साधारण पायथन स्क्रिप्ट लिखने की कोशिश कर रहा हूं जो सब (सब अपवादों के साथ) सब उपनिर्देशिकाओं में एक index.tpl को index.html पर कॉपी करेगा।
मैं उपनिर्देशिकाओं की सूची प्राप्त करने की कोशिश कर रहा हूँ।
मैं एक साधारण पायथन स्क्रिप्ट लिखने की कोशिश कर रहा हूं जो सब (सब अपवादों के साथ) सब उपनिर्देशिकाओं में एक index.tpl को index.html पर कॉपी करेगा।
मैं उपनिर्देशिकाओं की सूची प्राप्त करने की कोशिश कर रहा हूँ।
जवाबों:
मैंने सभी मौजूदा उपनिर्देशिकाओं के लिए पूर्ण पथ को वापस करने के लिए विभिन्न कार्यों पर कुछ गति परीक्षण किया ।
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
है: 3x से तेज walk
, 32x से तेज listdir
(फिल्टर से), 35x से तेज Pathlib
और 36x से तेज listdir
और 37x (() से तेज है glob
!
Scandir: 0.977
Walk: 3.011
Listdir (filter): 31.288
Pathlib: 34.075
Listdir: 35.501
Glob: 36.277
W7x64, पायथन 3.8.1 के साथ परीक्षण किया गया। 440 सबफ़ोल्डर के साथ फ़ोल्डर।
यदि आप आश्चर्य करते हैं कि क्या listdir
दो बार os.path.join () नहीं करने से गति हो सकती है, लेकिन अंतर मूल रूप से अनुपलब्ध है।
कोड:
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}")
import os
def get_immediate_subdirectories(a_dir):
return [name for name in os.listdir(a_dir)
if os.path.isdir(os.path.join(a_dir, name))]
किसी ने उल्लेख क्यों नहीं किया glob
? glob
आपको यूनिक्स-शैली पाथनेम विस्तार का उपयोग करने की अनुमति देता है, और मेरी लगभग सभी चीजों के लिए काम करने वाला है जो एक से अधिक पथ नाम खोजने की आवश्यकता है। यह बहुत आसान बनाता है:
from glob import glob
paths = glob('*/')
नोट करें कि glob
अंतिम स्लैश के साथ निर्देशिका वापस आ जाएगी (यूनिक्स के रूप में) जबकि अधिकांश path
आधारित समाधान अंतिम स्लैश को छोड़ देंगे।
paths = [ p.replace('/', '') for p in glob('*/') ]
।
[p[:-1] for p in paths]
, क्योंकि प्रतिस्थापित विधि फ़ाइल नाम में किसी भी बची हुई आगे की स्लैश को बदल देगी (ऐसा नहीं है कि वे आम हैं)।
rstrip
इसके बजाय उपयोग करना चाहते हैं strip
, हालांकि, उत्तरार्द्ध किसी भी पूरी तरह से योग्य पथ को सापेक्ष पथ में बदल देगा।
strip('/')
शुरू करने वाले और पीछे आने वाले दोनों को हटा दूंगा / '', rstrip('/')
केवल पीछे वाले को हटा देगा
" वर्तमान निर्देशिका में सभी उपनिर्देशिकाओं की सूची प्राप्त करना " जांचें ।
यहाँ एक पायथन 3 संस्करण है:
import os
dir_list = next(os.walk('.'))[1]
print(dir_list)
(s.rstrip("/") for s in glob(parent_dir+"*/"))
अधिक समय कुशल है। मेरा सहज संदेह यह है कि एक- stat()
आधारित os.walk()
समाधान शैल-शैली के ग्लोबिंग की तुलना में गहरा होना चाहिए। दुख की बात है कि मेरे पास इच्छाशक्ति की कमी है timeit
और वास्तव में मुझे इसका पता है।
import os, os.path
एक निर्देशिका में (पूर्ण-पथ) तत्काल उप-निर्देशिका प्राप्त करने के लिए:
def SubDirPath (d):
return filter(os.path.isdir, [os.path.join(d,f) for f in os.listdir(d)])
नवीनतम (नवीनतम) उप-निर्देशिका प्राप्त करने के लिए:
def LatestDirectory (d):
return max(SubDirPath(d), key=os.path.getmtime)
list( filter(...) )
।
os.walk
इस स्थिति में आपका दोस्त है।
प्रलेखन से सीधे:
वॉक () एक डायरेक्टरी ट्री में फ़ाइल नाम जेनरेट करता है, वॉक करके ट्री या तो ऊपर या नीचे से ऊपर जाता है। निर्देशिका शीर्ष पर निहित पेड़ में प्रत्येक निर्देशिका के लिए (शीर्ष स्वयं सहित), यह एक 3-टपल (dirpath, dirnames, फ़ाइल नाम) देता है।
यह विधि अच्छी तरह से यह सब एक बार में करता है।
from glob import glob
subd = [s.rstrip("/") for s in glob(parent_dir+"*/")]
Twisted के FilePath मॉड्यूल का उपयोग करना:
from twisted.python.filepath import FilePath
def subdirs(pathObj):
for subpath in pathObj.walk():
if subpath.isdir():
yield subpath
if __name__ == '__main__':
for subdir in subdirs(FilePath(".")):
print "Subdirectory:", subdir
चूंकि कुछ टिप्पणीकारों ने पूछा है कि इसके लिए ट्विस्टेड पुस्तकालयों का उपयोग करने के क्या फायदे हैं, मैं यहां मूल प्रश्न से थोड़ा आगे जाऊंगा।
नहीं है कुछ बेहतर प्रलेखन एक शाखा है कि FilePath के फायदे बताते हैं में; आप इसे पढ़ना चाह सकते हैं।
विशेष रूप से इस उदाहरण में: मानक पुस्तकालय संस्करण के विपरीत, यह फ़ंक्शन बिना आयात के साथ लागू किया जा सकता है । "सबडिर्स" फ़ंक्शन पूरी तरह से सामान्य है, इसमें वह अपने तर्क के अलावा कुछ भी नहीं संचालित करता है। मानक लाइब्रेरी का उपयोग करके फ़ाइलों को कॉपी और स्थानांतरित करने के लिए, आपको " 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"))
ऊपर "सबडिरर्स" फ़ंक्शन किसी भी FilePath
तरह की वस्तु पर काम कर सकता है । जिसका अर्थ है, अन्य चीजों, ZipPath
वस्तुओं के बीच । दुर्भाग्य से ZipPath
अभी-अभी पढ़ा गया है, लेकिन इसे लेखन के समर्थन में बढ़ाया जा सकता है।
आप परीक्षण उद्देश्यों के लिए अपनी खुद की वस्तुओं को भी पास कर सकते हैं। यहाँ सुझाए गए os.path- उपयोग करने वाले API का परीक्षण करने के लिए, आपको आयात किए गए नामों और निहित निर्भरताओं के साथ बंदर करना होगा और आम तौर पर अपने परीक्षणों को काम करने के लिए काला जादू करना होगा। FilePath के साथ, आप कुछ इस तरह से करते हैं:
class MyFakePath:
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(...))
मैंने सिर्फ vmware वर्चुअल मशीन को स्थानांतरित करने के लिए कुछ कोड लिखे, और उप-निर्देशिकाओं के बीच फाइल कॉपी को पूरा करने os.path
और उपयोग shutil
करने के लिए समाप्त किया ।
def copy_client_files (file_src, file_dst):
for file in os.listdir(file_src):
print "Copying file: %s" % file
shutil.copy(os.path.join(file_src, file), os.path.join(file_dst, file))
यह बहुत सुरुचिपूर्ण नहीं है, लेकिन यह काम करता है।
यहाँ एक तरीका है:
import os
import shutil
def copy_over(path, from_name, to_name):
for path, dirname, fnames in os.walk(path):
for fname in fnames:
if fname == from_name:
shutil.copy(os.path.join(path, from_name), os.path.join(path, to_name))
copy_over('.', 'index.tpl', 'index.html')
मुझे path.py का उल्लेख करना है लाइब्रेरी , जिसका मैं बहुत बार उपयोग करता हूं।
तत्काल उपनिर्देशिका प्राप्त करना उतना ही सरल हो जाता है:
my_dir.dirs()
पूर्ण कार्य उदाहरण है:
from path import Path
my_directory = Path("path/to/my/directory")
subdirs = my_directory.dirs()
NB: my_directory अभी भी एक स्ट्रिंग के रूप में हेरफेर किया जा सकता है, क्योंकि पथ स्ट्रिंग का एक उपवर्ग है, लेकिन पथों में हेरफेर करने के लिए उपयोगी तरीकों का एक गुच्छा प्रदान करता है।
def get_folders_in_directories_recursively(directory, index=0):
folder_list = list()
parent_directory = directory
for path, subdirs, _ in os.walk(directory):
if not index:
for sdirs in subdirs:
folder_path = "{}/{}".format(path, sdirs)
folder_list.append(folder_path)
elif path[len(parent_directory):].count('/') + 1 == index:
for sdirs in subdirs:
folder_path = "{}/{}".format(path, sdirs)
folder_list.append(folder_path)
return folder_list
निम्नलिखित समारोह के रूप में कहा जा सकता है:
get_folders_in_directories_recursively (डायरेक्टरी, इंडेक्स = 1) -> पहले स्तर में फ़ोल्डर्स की सूची देता है
get_folders_in_directories_recursively (निर्देशिका) -> सभी उप फ़ोल्डर देता है
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 location
return dirs
child_dirs
समारोह एक रास्ता एक निर्देशिका लेता है और की सूची लौटाता तत्काल उपनिर्देशिका उस में।
dir
|
-- dir_1
-- dir_2
child_dirs('dir') -> ['dir_1', 'dir_2']
import pathlib
def list_dir(dir):
path = pathlib.Path(dir)
dir = []
try:
for item in path.iterdir():
if item.is_dir():
dir.append(item)
return dir
except FileNotFoundError:
print('Invalid directory')
Pathlib का उपयोग कर एक लाइनर:
list_subfolders_with_paths = [p for p in pathlib.Path(path).iterdir() if p.is_dir()]