How to list only top level directories in Python?

I want to be able to list only the directories inside some folder. This means I don't want filenames listed, nor do I want additional sub-folders.

Let's see if an example helps. In the current directory we have:

>>> 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']

However, I don't want filenames listed. Nor do I want sub-folders such as \Lib\curses. Essentially what I want works with the following:

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

However, I'm wondering if there's a simpler way of achieving the same results. I get the impression that using os.walk only to return the top level is inefficient/too much.


Asked by: Lily633 | Posted: 24-09-2021






Answer 1

os.walk

Use os.walk with next item function:

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

For Python <=2.5 use:

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

How this works

os.walk is a generator and calling next will get the first result in the form of a 3-tuple (dirpath, dirnames, filenames). Thus the [1] index returns only the dirnames from that tuple.

Answered by: Kevin217 | Posted: 25-10-2021



Answer 2

Filter the result using os.path.isdir() (and use os.path.join() to get the real path):

>>> [ 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']

Answered by: David663 | Posted: 25-10-2021



Answer 3

Filter the list using os.path.isdir to detect directories.

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

Answered by: Tess500 | Posted: 25-10-2021



Answer 4

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

Answered by: Roman282 | Posted: 25-10-2021



Answer 5

Note that, instead of doing os.listdir(os.getcwd()), it's preferable to do os.listdir(os.path.curdir). One less function call, and it's as portable.

So, to complete the answer, to get a list of directories in a folder:

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

If you prefer full pathnames, then use this function:

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

Answered by: Wilson517 | Posted: 25-10-2021



Answer 6

This seems to work too (at least on linux):

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

Answered by: Leonardo789 | Posted: 25-10-2021



Answer 7

Using list comprehension,

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

I think It is the simplest way

Answered by: Adrian538 | Posted: 25-10-2021



Answer 8

Just to add that using os.listdir() does not "take a lot of processing vs very simple os.walk().next()[1]". This is because os.walk() uses os.listdir() internally. In fact if you test them together:

>>>> 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

The filtering of os.listdir() is very slightly faster.

Answered by: Kellan764 | Posted: 25-10-2021



Answer 9

A very much simpler and elegant way is to use this:

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

Run this script in the same folder for which you want folder names.It will give you exactly the immediate folders name only(that too without the full path of the folders).

Answered by: Dainton724 | Posted: 25-10-2021



Answer 10

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

Answered by: Aston990 | Posted: 25-10-2021



Answer 11

Python 3.4 introduced the pathlib module into the standard library, which provides an object oriented approach to handle filesystem paths:

from pathlib import Path

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

Answered by: Aida383 | Posted: 25-10-2021



Answer 12

You could also use os.scandir:

with os.scandir(os.getcwd()) as mydir:
    dirs = [i.name for i in mydir if i.is_dir()]

In case you want the full path you can use i.path.

Using scandir() instead of listdir() can significantly increase the performance of code that also needs file type or file attribute information, because os.DirEntry objects expose this information if the operating system provides it when scanning a directory.

Answered by: Rubie627 | Posted: 25-10-2021



Answer 13

being a newbie here i can't yet directly comment but here is a small correction i'd like to add to the following part of ΤΖΩΤΖΙΟΥ's answer :

If you prefer full pathnames, then use this function:

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

for those still on python < 2.4: the inner construct needs to be a list instead of a tuple and therefore should read like this:

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

otherwise one gets a syntax error.

Answered by: Miller562 | Posted: 25-10-2021



Answer 14

2021 answer using glob:

import glob, os

p = "/some/path/"
for d in glob.glob(p + "*" + os.path.sep):
  print(d)

Answered by: Emily941 | Posted: 25-10-2021



Answer 15

For a list of full path names I prefer this version to the other solutions here:

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))]

Answered by: Rafael758 | Posted: 25-10-2021



Answer 16

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

Answered by: Blake422 | Posted: 25-10-2021



Answer 17

Like so?

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

Answered by: Lily885 | Posted: 25-10-2021



Answer 18

FWIW, the os.walk approach is almost 10x faster than the list comprehension and filter approaches:

In [30]: %timeit [d for d in os.listdir(os.getcwd()) if os.path.isdir(d)]
1.23 ms ± 97.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [31]: %timeit list(filter(os.path.isdir, os.listdir(os.getcwd())))
1.13 ms ± 13.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [32]: %timeit next(os.walk(os.getcwd()))[1]
132 µs ± 9.34 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Answered by: Kate150 | Posted: 25-10-2021



Answer 19

Using python 3.x with pathlib.Path.iter_dir

$ mkdir tmpdir
$ mkdir -p tmpdir/a/b/c
$ mkdir -p tmpdir/x/y/z

$ touch tmpdir/a/b/c/abc.txt
$ touch tmpdir/a/b/ab.txt
$ touch tmpdir/a/a.txt

$ python --version
Python 3.7.12
>>> from pathlib import Path
>>> tmpdir = Path("./tmpdir")
>>> [d for d in tmpdir.iterdir() if d.is_dir]
[PosixPath('tmpdir/x'), PosixPath('tmpdir/a')]
>>> sorted(d for d in tmpdir.iterdir() if d.is_dir)
[PosixPath('tmpdir/a'), PosixPath('tmpdir/x')]

Answered by: Ada298 | Posted: 25-10-2021



Answer 20

A safer option that does not fail when there is no directory.

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 []

Answered by: John697 | Posted: 25-10-2021



Answer 21

-- 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

Answered by: Cherry504 | Posted: 25-10-2021



Similar questions

filesystems - Python - Swap two file directories with each other

I have a robot and it is set up in a way to take commands from the front end of the website to then run a command on the robot. For example if command == 'CF': os.system('aplay /home/pi/sound/wavycf.wav') I need somthing that will swap two files /images/hud.png and images/special/hud.png to each others directories....I hope that makes sense


filesystems - Python - Swap two file directories with each other

I have a robot and it is set up in a way to take commands from the front end of the website to then run a command on the robot. For example if command == 'CF': os.system('aplay /home/pi/sound/wavycf.wav') I need somthing that will swap two files /images/hud.png and images/special/hud.png to each others directories....I hope that makes sense


filesystems - Python trouble importing modules

I am building a web app with this directory structure: app/ __init__.py config/ __init__.py db_config.py models/ __init__.py model.py datasources/ __init__.py database.py ... ... Every __init__.py file has __all__ = ['', '', ...] in it, listing the .py files that are in th...


filesystems - Python: Help with counters and writing files

This question already has answers here:


filesystems - Python: How do I create sequential file names?

I want my program to be able to write files in a sequential format, ie: file1.txt, file2.txt, file3.txt. It is only meant to write a single file upon execution of the code. It can't overwrite any existing files, and it MUST be created. I'm stumped.


filesystems - Python: problem with tiny script to delete files

I have a project that used to be under SVN, but now I'm moving it to Mercurial, so I want to clear out all the .svn files. It's a little too big to do it by hand, so I decided to write a python script to do it. But it isn't working. def cleandir(dir_path): print "Cleaning %s\n" % dir_path toDelete = [] files = os.listdir(dir_path) for filedir in files: print "considering %s" ...


windows - How can I enumerate filesystems from Python?

I'm using os.statvfs to find out the free space available on a volume -- in addition to querying free space for a particular path, I'd like to be able to iterate over all volumes. I'm working on Linux at the moment, but ideally would like something which returns ["/", "/boot", "home"] on Linux and ["C:\", "D:\"] on Windows.


filesystems - finding out absolute path to a file from python

If I have a file test.py that resides in some directory, how can I find out from test.py what directory it is in? os.path.curdir will give the current directory but not the directory where the file lives. If I invoke test.py from some directory foo, os.curdir will return foo but not the path of test.py. thanks.


filesystems - Pythonic way to modify python path relative to current directory

I have a project that is structured like this (cut down a lot to give the gist)... State_Editor/ bin/ state_editor/ __init__.py main.py features/ __init__.py # .py files io/ __init__.py # .py files # etc. You get the idea. Now say for example that foobar.py in features ...


filesystems - Override file operations in Python

Is there a way to override all file operations in Python? File operations such as 'open', 'os.rename' and 'os.unlink'. I want to create a temporary, in-memory file system without rewriting a library. Does anyone know of a script or a library that has this feature? I want to run a library on Google App Engine and it is not possible to write to the file system.


filesystems - Python - Remove accents from all files in folder

I'm trying to remove all accents from a all coding files in a folder.. I already have success in building the list of files, the problem is that when I try to use unicodedata to normalize I get the error: ** Traceback (most recent call last): File "/usr/lib/gedit-2/plugins/pythonconsole/console.py", line 336, in __run exec command in self.namespace File "", line 2, in UnicodeDecodeError: 'utf8' codec can't decode ...


filesystems - In Python, how can I get the file system of a given file path

In python, given a directory or file path like /usr/local, I need to get the file system where its available. In some systems it could be / (root) itself and in some others it could be /usr. I tried os.statvfs it doesnt help. Do I have to run the df command with the path name and extract the file system from the output? Is there a better solution? Its for linux/unix platforms only. Thanks






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top