os.listdir

listdir gives bare names in no promised order — sort them yourself, and join them with the folder before using them. scandir is faster when you also need to know file vs folder (or the size), because the directory read already returned that information.

os functionPython 3.0+ (scandir, DirEntry 3.5+)Live demo
Common call
sorted(os.listdir('data'))
Returns
['a.csv', 'b.csv', 'raw']
Replaces
Shelling out to ls / dir; glob.glob("*") when you want hidden files too
Watch out
Names only — os.path.isfile(name) checks the current folder, not the listed one
os.listdir(pathpath — The folder to list. bytes in → bytes names out. An open directory file descriptor also works on Unix.type: str | bytes | PathLike | int · default: '.'='.') / os.scandir(path='.')
→ list[str] | iterator of DirEntry

Demo

Live evaluation
Create some files (folders appear on the way) and list one folder. sorted() because the order is up to the file system.
Try:
Inputs
fileslist[str]files to create, comma-separated
folderstrfolder to list
Code
import os
for f in ['main.py', '.env', 'docs/index.md', 'docs/api.md']:
    os.makedirs(os.path.dirname(f) or '.', exist_ok=True)
    open(f, 'w').close()
try:
    result = sorted(os.listdir('.'))
except OSError as e:
    result = type(e).__name__
result
Result
['.env', 'docs', 'main.py']

listdir includes hidden names such as '.env' (it never adds '.' or '..') and mixes files and folders. A missing folder raises FileNotFoundError — the class is the same everywhere, the message text differs between Linux and Windows. In the files-only tab the names come back without their folder, so os.path.join(folder, n) is essential: isfile('app.py') would look in the current folder and say False.

Parameters

NameTypeRequiredDescription
pathstr | bytes | PathLike | intno ('.')The folder to list. bytes in → bytes names out. An open directory file descriptor also works on Unix.

Return value

list[str] | iterator of DirEntry — listdir: the names (no '.' or '..'), in arbitrary order. scandir: an iterator of DirEntry objects (use it in a with block).

Common patterns

Folders only, with scandir
No extra stat call per entry on most systems.
import os
with os.scandir(path) as it:
    subdirs = sorted(e.name for e in it if e.is_dir())
Files by extension
endswith accepts a tuple.
import os
images = [n for n in os.listdir(folder) if n.lower().endswith(('.png', '.jpg'))]
Largest files in a folder
DirEntry.stat() is cached and, on Windows, free.
import os
with os.scandir(folder) as it:
    sizes = sorted(((e.stat().st_size, e.name) for e in it if e.is_file()), reverse=True)
Skip hidden entries (POSIX convention)
Hidden means "starts with a dot" on Linux and macOS.
import os
visible = [n for n in os.listdir('.') if not n.startswith('.')]

Examples

1. Names, sorted
import os for name in ['b.txt', 'a.txt']: open(name, 'w').close() os.mkdir('sub') sorted(os.listdir())
Returns
['a.txt', 'b.txt', 'sub']
2. Hidden files are included
import os open('.hidden', 'w').close() open('shown', 'w').close() sorted(os.listdir('.'))
Returns
['.hidden', 'shown']
3. An empty folder
import os os.mkdir('empty') os.listdir('empty')
Returns
[]
4. bytes in, bytes out
import os os.mkdir('data') open('data/a.csv', 'w').close() os.listdir(b'data')
Returns
[b'a.csv']
5. scandir: name, is_dir, is_file
import os open('x.py', 'w').close() os.mkdir('pkg') with os.scandir('.') as it: entries = sorted((e.name, e.is_dir(), e.is_file()) for e in it) entries
Returns
[('pkg', True, False), ('x.py', False, True)]
6. DirEntry.stat() for sizes
import os with open('big.bin', 'wb') as f: f.write(b'x' * 10) with os.scandir('.') as it: sizes = {e.name: e.stat().st_size for e in it} sizes
Returns
{'big.bin': 10}
7. A DirEntry is path-like
import os open('f.txt', 'w').close() with os.scandir('.') as it: e = next(it) (type(e).__name__, isinstance(e, os.PathLike), e.name)
Returns
('DirEntry', True, 'f.txt')
8. Errors carry errno and filename
import os try: os.listdir('missing') except FileNotFoundError as e: info = (type(e).__name__, e.errno, e.filename) info
Returns
('FileNotFoundError', 2, 'missing')

Pitfalls

1. Using the bare name from listdir
listdir returns names relative to the listed folder. Without join, isfile/open look in the current folder.
isfile(name)
import os
os.mkdir('d')
open('d/a.txt', 'w').close()
[n for n in os.listdir('d') if os.path.isfile(n)]
[]
isfile(join(folder, name))
import os
os.mkdir('d')
open('d/a.txt', 'w').close()
[n for n in os.listdir('d') if os.path.isfile(os.path.join('d', n))]
['a.txt']
2. Relying on the listing order
The order depends on the file system (NTFS happens to be alphabetical, ext4 is not). Sort when order matters.
listdir order
import os
for n in ['c', 'a', 'b']:
    open(n, 'w').close()
len(os.listdir('.'))
3
sorted()
import os
for n in ['c', 'a', 'b']:
    open(n, 'w').close()
sorted(os.listdir('.'))
['a', 'b', 'c']
3. Leaving a scandir iterator open
An unfinished scandir iterator keeps the directory handle open until it is closed or garbage-collected — then CPython emits "ResourceWarning: unclosed scandir iterator". Closing by hand is easy to forget; use with.
manual close()
import os
open('a', 'w').close()
it = os.scandir('.')
first = next(it).name
it.close()
first
'a'
with os.scandir()
import os
open('a', 'w').close()
with os.scandir('.') as it:
    first = next(it).name
first
'a'

When to use

Use it
  • One folder, names only → listdir
  • One folder, and you need is_dir / is_file / sizes → scandir
Reach for something else
  • A whole tree → os.walk (or Path.rglob)
  • Pattern matching (*.csv) → glob.glob or Path.glob
  • Object paths → Path.iterdir()

Notes

CPython impl
Both are C functions in Modules/posixmodule.c (readdir on POSIX, FindFirstFileW / FindNextFileW on Windows); os.walk is built on scandir
DirEntry
name, path (folder joined with name, using the OS separator), is_dir(), is_file(), is_symlink(), is_junction() (3.12+), stat(), inode(). Results are cached; Windows already has the stat data from the directory read
scandir
Added in 3.5 (PEP 471); context-manager support since 3.6; DirEntry became a public class (os.DirEntry) in 3.6

FAQ

sorted(os.listdir(folder)) for names. For files only: [n for n in os.listdir(folder) if os.path.isfile(os.path.join(folder, n))] — or with scandir: [e.name for e in os.scandir(folder) if e.is_file()].