os.path.sep
os.path is posixpath on Linux and macOS and ntpath on Windows, and these constants are what differ between the two. Every one except supports_unicode_filenames is also available directly on os (os.sep, os.pathsep, os.devnull ...). To show both platforms the examples import posixpath and ntpath explicitly.
Common call
os.environ['PATH'].split(os.pathsep)
Returns
sep '/' or '\\', pathsep ':' or ';', devnull '/dev/null' or 'nul'
Replaces
Hard-coded '/', ':' and '/dev/null'
Watch out
Splitting paths on sep misses altsep on Windows: use os.path.split or pathlib
os.path.sep · altsep · extsep · curdir · pardir · pathsep · defpath · devnull · supports_unicode_filenames
→ str | None | bool
Common patterns
Split and extend PATH-like variables
pathsep is the separator between entries of PATH, PYTHONPATH and similar variables.
import os dirs = os.environ.get('PATH', os.defpath).split(os.pathsep) os.environ['PATH'] = os.pathsep.join(['/opt/tool/bin', *dirs])
Throw away a subprocess output
devnull names the null device; subprocess.DEVNULL is usually simpler.
import os, subprocess with open(os.devnull, 'w') as sink: subprocess.run(['git', 'status'], stdout=sink)
Accept both separators
On Windows a path may use / or \; altsep is None on POSIX, so filter it out.
import os seps = tuple(s for s in (os.sep, os.altsep) if s) is_dir_like = 'logs/'.endswith(seps)
Examples
1. sep and altsep on each platform
import posixpath, ntpath
(posixpath.sep, posixpath.altsep, ntpath.sep, ntpath.altsep)
Returns
('/', None, '\\', '/')2. pathsep separates PATH entries
import posixpath, ntpath
(posixpath.pathsep, ntpath.pathsep)
Returns
(':', ';')3. Splitting a PATH value
import posixpath
'/usr/local/bin:/usr/bin:/bin'.split(posixpath.pathsep)
Returns
['/usr/local/bin', '/usr/bin', '/bin']4. curdir, pardir and extsep are the same everywhere
import posixpath, ntpath
(posixpath.curdir, posixpath.pardir, posixpath.extsep) == (ntpath.curdir, ntpath.pardir, ntpath.extsep) == ('.', '..', '.')
Returns
True5. The null device and the default search path
import posixpath, ntpath
(posixpath.devnull, ntpath.devnull, posixpath.defpath, ntpath.defpath)
Returns
('/dev/null', 'nul', '/bin:/usr/bin', '.;C:\\bin')6. os re-exports the same values
import os
all(getattr(os, n) == getattr(os.path, n) for n in ['sep', 'altsep', 'extsep', 'curdir', 'pardir', 'pathsep', 'defpath', 'devnull'])
Returns
True7. supports_unicode_filenames is os.path only
import os, ntpath
(ntpath.supports_unicode_filenames, hasattr(os, 'supports_unicode_filenames'))
Returns
(True, False)8. Writing to devnull discards the data
import os
with open(os.devnull, 'w') as f:
n = f.write('gone')
n
Returns
4Pitfalls
1. Splitting a Windows path on sep only
Windows accepts both \ and /, and user input often mixes them. split(sep) misses the forward slashes; PureWindowsPath (or ntpath.split) knows both.
split(ntpath.sep)
import ntpath r'C:/data\logs\app.txt'.split(ntpath.sep)
['C:/data', 'logs', 'app.txt']
PureWindowsPath.parts
from pathlib import PureWindowsPath PureWindowsPath(r'C:/data\logs\app.txt').parts
('C:\\', 'data', 'logs', 'app.txt')
2. Mixing up sep and pathsep
sep separates folders inside one path; pathsep separates whole paths in PATH-like variables.
split on sep
import posixpath '/usr/bin:/bin'.split(posixpath.sep)
['', 'usr', 'bin:', 'bin']
split on pathsep
import posixpath '/usr/bin:/bin'.split(posixpath.pathsep)
['/usr/bin', '/bin']
3. Gluing paths together with sep
String concatenation doubles separators and ignores absolute parts; join handles both.
'a/' + sep + 'b'
import posixpath 'data/' + posixpath.sep + 'file.txt'
'data//file.txt'
join
import posixpath posixpath.join('data/', 'file.txt')
'data/file.txt'
When to use
Use it
- Splitting or building PATH-like environment variables (pathsep)
- Opening the null device by name (devnull)
- Checking whether a string ends with a separator, accepting altsep too
Reach for something else
- Joining or splitting paths → os.path.join / os.path.split / pathlib
- Line endings → os.linesep is a different constant, and text mode already translates \n
- Silencing subprocess output → subprocess.DEVNULL
Notes
CPython impl
Plain module-level assignments at the top of Lib/posixpath.py and Lib/ntpath.py; Lib/os.py re-exports eight of them with from os.path import curdir, pardir, sep, pathsep, defpath, extsep, altsep, devnull
posixpath
sep '/', altsep None, pathsep ':', defpath '/bin:/usr/bin', devnull '/dev/null'. supports_unicode_filenames is True only on macOS (sys.platform == 'darwin')
ntpath
sep '\\', altsep '/', pathsep ';', defpath '.;C:\\bin', devnull 'nul', supports_unicode_filenames True
Everywhere
curdir '.', pardir '..', extsep '.'
FAQ
The values depend on the operating system running Python, and a browser has none. The examples import posixpath and ntpath by name, which works on every OS, so they show both sets of values.