os.sep

Every value here depends on the OS Python runs on: os.sep is '/' on Linux and macOS and a backslash on Windows. os.path itself is just an alias - it IS the posixpath module on Linux/macOS and the ntpath module on Windows - so you can import either one directly to get the other platform's values and rules anywhere.

os constantsPython 3 (all)
Common call
os.path.join(folder, name) # instead of folder + os.sep + name
Returns
'/' on POSIX, '\\' on Windows (os.sep)
Replaces
Hard-coded '/', '\\', ':', ';', '\\r\\n' and '/dev/null'
Watch out
Never write os.linesep to a text-mode file - write '\\n'
os.sep, os.altsep, os.extsep, os.curdir, os.pardir, os.pathsep, os.linesep, os.defpath, os.devnull, os.name, os.path
→ str | None | module

Common patterns

Silence a child process
os.devnull is the right null device name on every OS (subprocess.DEVNULL does the same without opening a file).
import os
import subprocess
with open(os.devnull, 'w') as sink:
    subprocess.run(['git', 'fetch'], stdout=sink, stderr=sink)
Split PATH-style variables
os.pathsep is the separator between entries of PATH, PYTHONPATH and similar variables.
import os
dirs = os.environ.get('PATH', os.defpath).split(os.pathsep)
Use the other platform's path rules
os.path is posixpath or ntpath; import the other one to handle foreign paths (URLs, zip members, Windows paths read on Linux).
import ntpath
import posixpath
posixpath.join('static', 'img', 'logo.png')   # always '/'
ntpath.splitdrive('C:\\Users\\ada')          # Windows rules on any OS
Branch on the OS family
os.name is 'posix' or 'nt'. Use sys.platform to tell Linux from macOS.
import os
import sys
if os.name == 'nt':
    config_dir = os.environ['APPDATA']
elif sys.platform == 'darwin':
    config_dir = os.path.expanduser('~/Library/Application Support')
else:
    config_dir = os.path.expanduser('~/.config')

Examples

1. Both separators, on any OS
import ntpath import posixpath (posixpath.sep, ntpath.sep, posixpath.altsep, ntpath.altsep)
Returns
('/', '\\', None, '/')
2. os.path is posixpath or ntpath
import ntpath import os import posixpath (os.path in (posixpath, ntpath), os.path.sep == os.sep, os.name in ('posix', 'nt'))
Returns
(True, True, True)
3. pathsep splits PATH
import posixpath '/usr/local/bin:/usr/bin'.split(posixpath.pathsep)
Returns
['/usr/local/bin', '/usr/bin']
4. curdir and pardir
import posixpath posixpath.normpath(posixpath.join('a', posixpath.curdir, 'b', posixpath.pardir, 'c'))
Returns
'a/c'
5. extsep builds a file name
import os 'report' + os.extsep + 'csv'
Returns
'report.csv'
6. defpath and devnull per platform
import ntpath import posixpath [(posixpath.defpath, posixpath.devnull), (ntpath.defpath, ntpath.devnull)]
Returns
[('/bin:/usr/bin', '/dev/null'), ('.;C:\\bin', 'nul')]
7. Writing to os.devnull discards
import os with open(os.devnull, 'w') as f: n = f.write('discarded') (n, open(os.devnull).read())
Returns
(9, '')
8. linesep is one of two values
import os os.linesep in ('\n', '\r\n')
Returns
True

Pitfalls

1. Splitting a Windows path on os.sep
Windows accepts '/' too (that is altsep), so splitting on the backslash alone misses separators. Let the path module split it.
split(sep)
import ntpath
'C:/data/report.txt'.split(ntpath.sep)
['C:/data/report.txt']
ntpath.split
import ntpath
ntpath.split('C:/data/report.txt')
('C:/data', 'report.txt')
2. Writing os.linesep in text mode
Text mode already turns '\n' into the platform line ending. On Windows os.linesep is '\r\n', so writing it produces '\r\r\n'. Here newline='\r\n' makes the file behave like a Windows text file on every OS.
write os.linesep
with open('out.txt', 'w', newline='\r\n') as f:
    f.write('line' + '\r\n')
open('out.txt', 'rb').read()
b'line\r\r\n'
write '\n'
with open('out.txt', 'w', newline='\r\n') as f:
    f.write('line' + '\n')
open('out.txt', 'rb').read()
b'line\r\n'
3. Confusing sep and pathsep
sep separates the parts of ONE path; pathsep separates whole paths in a list such as PATH.
split(sep)
import posixpath
'/usr/bin:/bin'.split(posixpath.sep)
['', 'usr', 'bin:', 'bin']
split(pathsep)
import posixpath
'/usr/bin:/bin'.split(posixpath.pathsep)
['/usr/bin', '/bin']

When to use

Use it
  • Splitting PATH-like variables (pathsep), discarding output (devnull), branching on the OS family (name)
  • Handling the other platform's paths: import posixpath or ntpath directly
Reach for something else
  • Joining or splitting paths by hand → os.path.join / os.path.split or pathlib
  • Line endings in text files → write "\n" and let text mode translate
  • Telling Linux from macOS → sys.platform or platform.system()
  • Temporary file names (TMP_MAX) → the tempfile module

Notes

CPython impl
Lib/os.py: on POSIX it sets name = 'posix', linesep = '\n' and does import posixpath as path; on Windows name = 'nt', linesep = '\r\n', import ntpath as path. It then registers sys.modules['os.path'] = path and imports curdir, pardir, sep, pathsep, defpath, extsep, altsep and devnull from it - so os.sep is os.path.sep
Values
posixpath: sep '/', altsep None, pathsep ':', defpath '/bin:/usr/bin', devnull '/dev/null'. ntpath: sep '\\', altsep '/', pathsep ';', defpath '.;C:\\bin', devnull 'nul'. Both: extsep '.', curdir '.', pardir '..'
os.name
'posix' on Linux and macOS, 'nt' on Windows. The docs also list 'java' as registered. sys.platform ('linux', 'darwin', 'win32') is finer-grained
TMP_MAX
Undocumented: the C library TMP_MAX limit (how many unique names tmpnam() can generate) - 238328 on Linux glibc and 2147483647 on Windows CPython 3.13. Python no longer has tmpnam; use tempfile

FAQ

Every value here depends on the OS running Python, so a live result would only show our server's values. The examples compare against posixpath and ntpath, which have fixed values on every machine. Note that os.name is 'posix' on macOS as well as Linux; use sys.platform ('darwin') or platform.system() ('Darwin') to tell them apart.