Windows applications often need to discover which drives are available before searching for files, creating backups, or presenting storage choices. Python provides os.listdrives(), a dedicated function that returns the roots of the drives currently known to the system.
This avoids fragile loops over letters from A to Z, shell commands, and third-party dependencies. This guide explains the return value, platform checks, integration with pathlib, removable and network drives, free-space checks, path validation, testing, and safe automation patterns.
What os.listdrives returns
The function returns a list of strings representing absolute drive roots. A typical result may contain C:\, D:\, and letters assigned to partitions, USB devices, optical drives, or mapped network locations.
import os
for drive in os.listdrives():
print(drive)
Being present in the list does not guarantee successful access. A removable device may be ejected, a network drive may be disconnected, and permissions may deny reading.
Platform availability
os.listdrives() is Windows-specific. Cross-platform code should check the operating system before calling it.
import os
import sys
if sys.platform == "win32":
roots = os.listdrives()
else:
roots = ["/"]
This keeps platform-specific logic isolated. Linux and macOS use mount points rather than Windows drive letters.
Converting roots to Path objects
pathlib.Path makes path composition and inspection easier.
from pathlib import Path
import os
roots = [Path(value) for value in os.listdrives()]
for root in roots:
print(root, root.exists())
Rechecking availability is useful because device state can change between discovery and access.
Checking free space
Backup tools commonly need available capacity. Combine the roots with shutil.disk_usage().
import os
import shutil
for root in os.listdrives():
try:
total, used, free = shutil.disk_usage(root)
except OSError as error:
print(root, "unavailable:", error)
continue
print(root, free // (1024 ** 3), "GB free")
Handling OSError is essential for removable media, empty readers, and unstable network mappings.
Removable media
A USB drive can disappear after the list is created. Do not cache drive results indefinitely when external devices matter. Refresh the list before opening a selector or starting an important operation.
Do not assume a removable device always receives the same letter. Windows may assign a different root on a later connection.
Network drives
Mapped network drives may appear with local disks. They can require credentials, add latency, or become temporarily unreachable. Code that scans every root should tolerate failures and let users exclude slow destinations.
UNC locations such as \\server\share may not appear unless mapped to a letter. Therefore, listdrives() does not replace explicit configuration of known network shares.
Filtering accessible roots
from pathlib import Path
import os
def accessible_roots():
result = []
for value in os.listdrives():
root = Path(value)
try:
next(root.iterdir(), None)
except (OSError, PermissionError):
continue
result.append(root)
return result
Listing a directory can be expensive on some devices, so perform this check only when access confirmation is necessary.
Looking for a known file or folder
When the relative path is known, test the direct candidate instead of recursively scanning entire disks.
from pathlib import Path
import os
def find_at_roots(name):
found = []
for value in os.listdrives():
candidate = Path(value) / name
try:
if candidate.exists():
found.append(candidate)
except OSError:
pass
return found
For broad searches, add depth limits, filters, progress reporting, and cancellation.
Validating user-supplied paths
Never trust text concatenation for destructive operations. Resolve the destination and confirm that it remains inside an allowed root.
from pathlib import Path
def inside_root(root, relative):
base = Path(root).resolve()
destination = (base / relative).resolve()
return destination == base or base in destination.parents
Require extra confirmation before deleting or overwriting data, and never let an empty relative value accidentally target the whole drive.
Building a drive selector
import os
drives = os.listdrives()
for index, drive in enumerate(drives, start=1):
print(f"{index}. {drive}")
Validate the selected index and refresh the list before a long operation because the underlying devices may have changed.
Error handling
Typical exceptions include OSError, PermissionError, and FileNotFoundError. Record which root failed and continue with other drives when that is safe. User-facing applications should explain whether the problem involves permissions, disconnected storage, or missing media.
Testing
Tests should not depend on the real letters of the machine running them. Wrap discovery in a function and inject a fake provider.
def choose_roots(list_roots):
return [root for root in list_roots() if root]
Tests can then cover an empty list, one drive, inaccessible drives, duplicates, and changes between calls without touching real storage.
When not to use os.listdrives
If the program already receives a configured directory, scanning every drive is unnecessary. For known user folders, prefer environment variables and platform APIs. On Linux servers, work with mount points instead of trying to reproduce Windows drive semantics.
Related content
Read the Academify guides about the os module, pathlib, large files, and exception handling. The official os documentation and shutil documentation provide the API details.
Best practices
Refresh the list before important work, handle failures per drive, avoid fixed-letter assumptions, limit searches, and validate external paths. Keep Windows-specific code inside a small, testable function in cross-platform projects.
Conclusion
os.listdrives() provides a direct, standard way to discover Windows drives. Combined with pathlib, shutil, validation, and careful exception handling, it supports reliable storage selectors, backup utilities, and file automation. Treat the result as a temporary snapshot: devices, networks, and permissions can change between calls, so every important access still needs verification.







