ไม่รวมไดเรกทอรีใน os.walk


148

ฉันกำลังเขียนสคริปต์ที่ลงไปในแผนผังไดเรกทอรี (โดยใช้ os.walk ()) จากนั้นเยี่ยมชมแต่ละไฟล์ที่ตรงกับนามสกุลไฟล์ที่แน่นอน อย่างไรก็ตามเนื่องจากต้นไม้ไดเรกทอรีบางส่วนที่เครื่องมือของฉันจะใช้ในนั้นยังมีไดเรกทอรีย่อยที่ในทางกลับกันมีจำนวนมากของไร้ประโยชน์ (สำหรับวัตถุประสงค์ของการสคริปต์นี้) สิ่งที่ฉันคิดว่าฉันต้องการเพิ่มตัวเลือกสำหรับผู้ใช้เพื่อระบุ รายการไดเรกทอรีที่จะแยกออกจากการแวะผ่าน

มันง่ายพอกับ os.walk () ท้ายที่สุดมันก็ขึ้นอยู่กับฉันที่จะตัดสินใจว่าจริง ๆ แล้วฉันต้องการไปที่ไฟล์ / dirs ที่เกี่ยวข้องโดย os.walk () หรือข้ามพวกเขา ปัญหาคือถ้าฉันมีต้นไม้ไดเรกทอรีเช่นนี้

root--
     |
     --- dirA
     |
     --- dirB
     |
     --- uselessStuff --
                       |
                       --- moreJunk
                       |
                       --- yetMoreJunk

และฉันต้องการยกเว้นuselessStuffและลูก ๆ ของมัน os.walk () จะยังคงสืบเชื้อสายมาจากไดเรกทอรีย่อย (อาจมีหลายพันรายการ) ของuselessStuffซึ่งไม่จำเป็นต้องพูดช้าลงสิ่งต่าง ๆ มากมาย ในโลกอุดมคติฉันสามารถบอก os.walk () เพื่อไม่ให้รำคาญที่จะให้ลูก ๆ ที่ไร้ประโยชน์อีกต่อไป แต่เพื่อความรู้ของฉันไม่มีทางที่จะทำเช่นนั้นได้ (มีไหม)

ไม่มีใครมีความคิด? อาจมีห้องสมุดบุคคลที่สามที่ให้สิ่งนั้นใช่ไหม

คำตอบ:


243

การแก้ไขแบบdirs in-placeจะตัดไฟล์และไดเร็กทอรีที่ตามมาที่เข้าชมโดยos.walk:

# exclude = set([...])
for root, dirs, files in os.walk(top, topdown=True):
    dirs[:] = [d for d in dirs if d not in exclude]

จากความช่วยเหลือ (os.walk):

เมื่อ topdown เป็นจริงผู้เรียกสามารถแก้ไขรายการ dirnames แบบแทน (เช่นผ่านการมอบหมายเดลหรือสไลซ์) และการเดินจะลดค่าลงในไดเรกทอรีย่อยที่ชื่อยังคงอยู่ใน dirnames; สามารถใช้เพื่อตัดการค้นหา ...


31
ทำไมdirs[:] =?
เบ็น

56
@ Ben: dirs[:] = valueปรับเปลี่ยนในสถานที่dirs มันเปลี่ยนเนื้อหาของรายการdirsโดยไม่ต้องเปลี่ยนภาชนะ ตามที่help(os.walk)กล่าวมาสิ่งนี้เป็นสิ่งจำเป็นหากคุณต้องการส่งผลกระทบต่อวิธีการos.walkสำรวจไดเรกทอรีย่อย ( dirs = valueเพียง reassigns (หรือ "ผูก") ตัวแปรdirsไปยังรายการใหม่โดยไม่มีการแก้ไขต้นฉบับdirs.)
unutbu

6
คุณยังสามารถใช้filter():dirs[:] = list(filter(lambda x: not x in exclude, dirs))
NuclearPeon

2
@ p014k: คุณสามารถเขียนฟังก์ชั่นเครื่องกำเนิดไฟฟ้าของคุณเองซึ่งสายos.walkและอัตราผลตอบแทนroot, dirs, filesหลังไม่รวม.git(หรือสิ่งอื่นที่คุณต้องการ) dirsจาก
unutbu

3
@unutbu เพียงแจ้งให้คุณทราบว่าในกรณีนี้การเพิ่มประสิทธิภาพนี้จะช่วยลดเวลาการสำรวจเส้นทางจากมากกว่า 100 วินาทีเหลือประมาณ 2 วินาที นั่นคือสิ่งที่ฉันเรียกว่าการเพิ่มประสิทธิภาพที่คุ้มค่า : D
antred

7

... รูปแบบทางเลือกของคำตอบที่ยอดเยี่ยมของ @ unutbu ที่อ่านโดยตรงอีกเล็กน้อยเนื่องจากความตั้งใจที่จะแยกไดเรกทอรีในราคา O (n ** 2) เทียบกับเวลา O (n)

(การทำสำเนาของรายการ dirs ด้วยlist(dirs)จำเป็นสำหรับการดำเนินการที่ถูกต้อง)

# exclude = set([...])
for root, dirs, files in os.walk(top, topdown=True):
    [dirs.remove(d) for d in list(dirs) if d in exclude]

5
dirs[:] = set(dirs) - excludeหากคุณต้องการที่จะเป็นตรงที่ค่าใช้จ่ายของหน่วยความจำบางอย่างที่คุณต้องการเขียนดีกว่า อย่างน้อยก็ยังเป็น \ $ O (n) \ $ และคุณไม่ต้องสร้างความเข้าใจสำหรับผลข้างเคียงของมันเท่านั้น ...
301_Moved_Permanently

3
มันไม่ได้เลวร้ายนัก แต่ก็ไม่ใช่ Python ที่เป็นสำนวนในความคิดของฉัน
Torsten Bronger

for d in list(dirs)ค่อนข้างแปลก dirsเป็นรายการอยู่แล้ว และสิ่งที่คุณมีไม่ใช่ความเข้าใจในรายการจริงๆ dirs.remove(d)จะไม่ส่งคืนสิ่งใดดังนั้นคุณจะจบลงด้วยรายการที่เต็มไปNoneด้วย ฉันเห็นด้วยกับ @Torsten
seanahern
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.