Làm thế nào để liệt kê chỉ các thư mục cấp cao nhất trong Python?


132

Tôi muốn chỉ có thể liệt kê các thư mục trong một số thư mục. Điều này có nghĩa là tôi không muốn tên tệp được liệt kê, tôi cũng không muốn các thư mục con bổ sung.

Hãy xem nếu một ví dụ giúp. Trong thư mục hiện tại, chúng tôi có:

>>> os.listdir(os.getcwd())
['cx_Oracle-doc', 'DLLs', 'Doc', 'include', 'Lib', 'libs', 'LICENSE.txt', 'mod_p
ython-wininst.log', 'NEWS.txt', 'pymssql-wininst.log', 'python.exe', 'pythonw.ex
e', 'README.txt', 'Removemod_python.exe', 'Removepymssql.exe', 'Scripts', 'tcl',
 'Tools', 'w9xpopen.exe']

Tuy nhiên, tôi không muốn tên tập tin được liệt kê. Tôi cũng không muốn các thư mục con như \ Lib \ curses. Về cơ bản những gì tôi muốn làm việc với những điều sau đây:

>>> for root, dirnames, filenames in os.walk('.'):
...     print dirnames
...     break
...
['cx_Oracle-doc', 'DLLs', 'Doc', 'include', 'Lib', 'libs', 'Scripts', 'tcl', 'Tools']

Tuy nhiên, tôi tự hỏi liệu có cách nào đơn giản hơn để đạt được kết quả tương tự. Tôi có ấn tượng rằng việc sử dụng os.walk chỉ để trả về mức cao nhất là không hiệu quả / quá nhiều.

Câu trả lời:


125

Lọc kết quả bằng os.path.itorir () (và sử dụng os.path.join () để có được đường dẫn thực):

>>> [ name for name in os.listdir(thedir) if os.path.isdir(os.path.join(thedir, name)) ]
['ctypes', 'distutils', 'encodings', 'lib-tk', 'config', 'idlelib', 'xml', 'bsddb', 'hotshot', 'logging', 'doc', 'test', 'compiler', 'curses', 'site-packages', 'email', 'sqlite3', 'lib-dynload', 'wsgiref', 'plat-linux2', 'plat-mac']

17
Việc này cần rất nhiều xử lý so với os.walk (). Next () [1]
Phyo Arkar Lwin

202

os.walk

Sử dụng os.walkvới nextchức năng mục:

next(os.walk('.'))[1]

Đối với Python <= 2.5 sử dụng:

os.walk('.').next()[1]

Làm thế nào điều này hoạt động

os.walklà một trình tạo và gọi nextsẽ nhận được kết quả đầu tiên dưới dạng 3-tuple (dirpath, dirnames, filenames). Do đó, [1]chỉ mục trả về chỉ dirnamestừ bộ dữ liệu đó.


14
Mô tả thêm một chút về điều này là đây là một máy phát điện, nó sẽ không đi theo các thư mục khác trừ khi bạn nói với nó. Vì vậy, .next () [1] thực hiện trong một dòng những gì tất cả các danh sách hiểu được. Có lẽ tôi sẽ làm một cái gì đó như thế DIRNAMES=1và sau đó next()[DIRNAMES]để dễ hiểu hơn cho những người duy trì mã trong tương lai.
thuyền viên

3
Giải pháp tuyệt vời +1. Để chỉ định một thư mục để duyệt, sử dụng:os.walk( os.path.join(mypath,'.')).next()[1]
Daniel Reis

42
cho python v3: next (os.walk ('.')) [1]
Andre Soares

nếu bạn sẽ làm nhiều hơn thì xử lý văn bản; tức là xử lý trong các thư mục thực tế sau đó có thể cần các đường dẫn đầy đủ:sorted( [os.path.join(os.getcwd(), item) for item in os.walk(os.curdir).next()[1]] )
DevPlayer

52

Lọc danh sách bằng os.path.itorir để phát hiện các thư mục.

filter(os.path.isdir, os.listdir(os.getcwd()))

5
Tôi nghĩ rằng đây là sự kết hợp tốt nhất giữa khả năng đọc và tính đồng nhất trong bất kỳ câu trả lời nào.
vergenzt

20
Điều này đã không làm việc. Tôi đoán là os.listdirtrả về một tên tệp / thư mục, được truyền vào os.path.isdir, nhưng cái sau cần một đường dẫn đầy đủ.
Daniel Reis

3
bộ lọc nhanh hơn os.walk timeit(os.walk(os.getcwd()).next()[1]) 1000 loops, best of 3: 734 µs per loop timeit(filter(os.path.isdir, os.listdir(os.getcwd()))) 1000 loops, best of 3: 477 µs per loop
B.Kocis

14
directories=[d for d in os.listdir(os.getcwd()) if os.path.isdir(d)]

4
Điều này có thể được rút ngắn để lọc (os.path.itorir, os.listdir (os.getcwd ())
John Millikin

3
Có ai có bất kỳ thông tin nào về việc bộ lọc hoặc hiểu danh sách nhanh hơn không? Nếu không thì nó chỉ là một lập luận chủ quan. Điều này tất nhiên giả định có 10 triệu thư mục trong cwd và hiệu suất là một vấn đề.
Mark Roddy

12

Lưu ý rằng, thay vì làm os.listdir(os.getcwd()), tốt hơn là nên làm os.listdir(os.path.curdir). Một cuộc gọi ít chức năng hơn và đó là cuộc gọi di động.

Vì vậy, để hoàn thành câu trả lời, để có được danh sách các thư mục trong một thư mục:

def listdirs(folder):
    return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]

Nếu bạn thích tên đường dẫn đầy đủ, sau đó sử dụng chức năng này:

def listdirs(folder):
    return [
        d for d in (os.path.join(folder, d1) for d1 in os.listdir(folder))
        if os.path.isdir(d)
    ]

9

Điều này dường như cũng hoạt động (ít nhất là trên linux):

import glob, os
glob.glob('*' + os.path.sep)

1
+1 cho glob. Nó có thể giúp bạn tiết kiệm rất nhiều mã, đặc biệt là các lần lặp và rất giống với việc sử dụng thiết bị đầu cuối UNIX ( ls)
Gerard

5
Thay vì glob.glob ( '*' + os.path.sep), bạn có thể muốn ghi [dir cho dir trong glob.glob ( "*") nếu os.path.isdir (dir)]
Eamonn MR

8

Chỉ cần thêm rằng sử dụng os.listdir () không "mất nhiều công sức xử lý so với os.walk (). Next () [1]" rất đơn giản . Điều này là do os.walk () sử dụng os.listdir () trong nội bộ. Trong thực tế nếu bạn kiểm tra chúng cùng nhau:

>>>> import timeit
>>>> timeit.timeit("os.walk('.').next()[1]", "import os", number=10000)
1.1215229034423828
>>>> timeit.timeit("[ name for name in os.listdir('.') if os.path.isdir(os.path.join('.', name)) ]", "import os", number=10000)
1.0592019557952881

Quá trình lọc os.listdir () nhanh hơn một chút.


2
Đến với Python 3.5 là cách nhanh hơn để nhận nội dung thư mục: python.org/dev/peps/pep-0471
foz

1
pep-0471 - scandirgói - sẵn sàng có sẵn cho Python 2.6 trở đi dưới dạng gói có thể cài đặt trên PyPI. Nó cung cấp thay thế cho os.walkos.listdirđó là nhanh hơn nhiều.
foz

6

Một cách rất đơn giản và thanh lịch là sử dụng điều này:

 import os
 dir_list = os.walk('.').next()[1]
 print dir_list

Chạy tập lệnh này trong cùng một thư mục mà bạn muốn có tên thư mục. Nó sẽ chỉ cung cấp cho bạn chính xác tên thư mục ngay lập tức (cũng không có đường dẫn đầy đủ của các thư mục).


6

Sử dụng hiểu danh sách,

[a for a in os.listdir() if os.path.isdir(a)]

Tôi nghĩ đó là cách đơn giản nhất


2

là một người mới ở đây tôi chưa thể bình luận trực tiếp nhưng đây là một chỉnh sửa nhỏ tôi muốn thêm vào phần sau của câu trả lời :

Nếu bạn thích tên đường dẫn đầy đủ, sau đó sử dụng chức năng này:

def listdirs(folder):  
  return [
    d for d in (os.path.join(folder, d1) for d1 in os.listdir(folder))
    if os.path.isdir(d)
]

đối với những người vẫn còn trên python <2.4 : cấu trúc bên trong cần phải là một danh sách thay vì một tuple và do đó nên đọc như sau:

def listdirs(folder):  
  return [
    d for d in [os.path.join(folder, d1) for d1 in os.listdir(folder)]
    if os.path.isdir(d)
  ]

nếu không thì sẽ bị lỗi cú pháp.


Tôi biết đã được một thời gian, nhưng ví dụ đầu tiên này thực sự giúp tôi.
Inbar Rose

1
Bạn gặp lỗi cú pháp vì phiên bản của bạn không hỗ trợ biểu thức trình tạo. Chúng được giới thiệu trong Python 2.4 trong khi danh sách hiểu đã có sẵn kể từ Python 2.0.
đánh thức

1
[x for x in os.listdir(somedir) if os.path.isdir(os.path.join(somedir, x))]

1

Để biết danh sách tên đường dẫn đầy đủ, tôi thích phiên bản này hơn các giải pháp khác tại đây:

def listdirs(dir):
    return [os.path.join(os.path.join(dir, x)) for x in os.listdir(dir) 
        if os.path.isdir(os.path.join(dir, x))]

1
scanDir = "abc"
directories = [d for d in os.listdir(scanDir) if os.path.isdir(os.path.join(os.path.abspath(scanDir), d))]

0

Một tùy chọn an toàn hơn mà không thất bại khi không có thư mục.

def listdirs(folder):
    if os.path.exists(folder):
         return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]
    else:
         return []

0

Thích như vậy?

>>>> [path for path in os.listdir(os.getcwd()) if os.path.isdir(path)]

0

Python 3.4 giới thiệu các pathlibmô-đun vào thư viện chuẩn, cung cấp một cách tiếp cận hướng đối tượng để xử lý đường dẫn hệ thống tập tin:

from pathlib import Path

p = Path('./')
[f for f in p.iterdir() if f.is_dir()]

-1
-- This will exclude files and traverse through 1 level of sub folders in the root

def list_files(dir):
    List = []
    filterstr = ' '
    for root, dirs, files in os.walk(dir, topdown = True):
        #r.append(root)
        if (root == dir):
            pass
        elif filterstr in root:
            #filterstr = ' '
            pass
        else:
            filterstr = root
            #print(root)
            for name in files:
                print(root)
                print(dirs)
                List.append(os.path.join(root,name))
            #print(os.path.join(root,name),"\n")
                print(List,"\n")

    return List
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.