The sys module in the Python standard library gives you access to Python system information and the interpreter's own runtime state. Use it to read command-line arguments, control how Python exits, inspect the module search path, write to standard error, and check the Python version at runtime.
import sys
print(sys.platform) # darwin
print(sys.version_info[:3]) # (3, 14, 6)
print(len(sys.argv)) # 1sys.platform identifies the operating system. sys.version_info is a named tuple with the Python version (major, minor, micro, release level, serial).
sys.argv is the list of command-line arguments; its length is 1 when no arguments are passed, because the script name is always the first element.
Reading command-line arguments
sys.argv is a list where the first item is the script name and the rest are the arguments the user passed.
import sys
if len(sys.argv) < 2:
print("Usage: python script.py <name>")
sys.exit(1)
name = sys.argv[1]
count = int(sys.argv[2]) if len(sys.argv) > 2 else 1
print(f"Hello, {name}! " * count)If you save this as greet.py and run python greet.py Maya 3 from the terminal, sys.argv captures the script name plus both arguments, and the greeting repeats three times:
Hello, Maya! Hello, Maya! Hello, Maya!sys.argv[0] is "greet.py". sys.argv[1] is "Maya". sys.argv[2] is "3", which we convert to an integer.
Always validate the length of sys.argv before accessing indices.
For complex argument parsing with flags, types, and help text, use argparse instead of raw sys.argv:
import argparse
parser = argparse.ArgumentParser(description="Greet someone.")
parser.add_argument("name", help="person to greet")
parser.add_argument("-c", "--count", type=int, default=1, help="number of times")
args = parser.parse_args()
print(f"Hello, {args.name}! " * args.count)argparse handles validation, type conversion, help text, and error messages automatically.
Exiting a program with sys.exit()
sys.exit() terminates the Python process and optionally returns an exit code to the operating system.
import sys
def divide(a, b):
if b == 0:
print("Error: division by zero", file=sys.stderr)
sys.exit(1)
return a / b
result = divide(10, 0)sys.exit(0) means success. sys.exit(1) (or any non-zero value) means failure.
The exit code is visible to shell scripts and CI pipelines that check $? after running your program.
sys.exit() raises SystemExit, which you can catch in tests or cleanup code:
import sys
try:
sys.exit(1)
except SystemExit as e:
print(f"Exit prevented in test. Code: {e.code}")Do not catch SystemExit in production code unless you have a specific reason, such as running cleanup before re-raising.
Standard I/O streams
The sys module exposes three file-like objects for input and output.
import sys
sys.stdout.write("Standard output\n")
sys.stderr.write("Standard error\n")Both lines show up in the terminal because it displays both streams together, but only stdout would be captured if you redirected the program's output to a file:
Standard output
Standard error| Stream | Purpose |
|---|---|
| sys.stdin | Standard input (keyboard, piped data) |
| sys.stdout | Standard output (terminal, redirected to file) |
| sys.stderr | Standard error (error messages, always visible) |
Use sys.stderr for error and diagnostic messages. This keeps them separate from normal output, so users can redirect stdout to a file and still see errors in the terminal.
To read all piped input at once:
import sys
if not sys.stdin.isatty():
data = sys.stdin.read()
print(f"Received {len(data)} characters from pipe")sys.stdin.isatty() returns True when input comes from a terminal and False when it comes from a pipe or file redirection.
Understanding sys.path
sys.path is a list of directories Python searches when you use import. It is initialized from the PYTHONPATH environment variable, the standard library location, and the directory containing the running script.
import sys
for p in sys.path[:5]:
print(p)The exact entries depend on how Python was installed and where the script lives, but the general shape is always the same, starting with the current directory and then the standard library locations:
/usr/lib/python314.zip
/usr/lib/python3.14
/usr/lib/python3.14/lib-dynload
/Users/maya/Dev/projectThe first entry (empty string) represents the current directory, which is why a script can always import sibling modules sitting next to it without any extra setup. You can add more directories to the search path at runtime:
import sys
sys.path.append("/Users/maya/my-libs")This is occasionally useful for development, but for production code, install your modules and packages properly with pip install -e . or by setting PYTHONPATH.
Checking the Python version
Use sys.version_info for programmatic version checks and sys.version for human-readable output.
import sys
print(sys.version)
if sys.version_info >= (3, 11):
print("Exception groups are available")
else:
print("Upgrade to Python 3.11+ for exception groups")sys.version prints the full interpreter build string, and since this example runs on Python 3.14, the version check also confirms exception groups are supported:
3.14.6 (main, Jul 4 2026, 10:00:00) [Clang 17.0.0]
Exception groups are availablesys.version_info is a named tuple with major, minor, micro, releaselevel, and serial. Compare it with tuples to check for minimum versions. Use this sparingly; most features are easier to check with try/except or hasattr.
Setting recursion limit
Python limits the depth of the call stack to prevent infinite recursion from crashing the interpreter. You can read and adjust this limit with sys.getrecursionlimit() and sys.setrecursionlimit().
import sys
print(sys.getrecursionlimit()) # 1000
sys.setrecursionlimit(2000)
print(sys.getrecursionlimit()) # 2000The default is typically 1000. Increasing it lets deeply recursive functions run longer, but setting it too high can cause a segmentation fault instead of a clean RecursionError. Only adjust this when you have a specific deep-recursion use case and have confirmed the algorithm cannot be rewritten iteratively.
Practical example: a simple CLI tool
Combine sys.argv, sys.exit, and sys.stderr into a small command-line utility.
import sys
def read_file(filename):
try:
with open(filename) as f:
return f.read()
except FileNotFoundError:
print(f"Error: '{filename}' not found", file=sys.stderr)
sys.exit(1)
except PermissionError:
print(f"Error: permission denied for '{filename}'", file=sys.stderr)
sys.exit(1)With the error-handling function defined, the rest of the script validates the arguments the user passed on the command line before calling it, so a missing filename never reaches the function at all:
if len(sys.argv) != 2:
print("Usage: python read.py <filename>", file=sys.stderr)
sys.exit(1)
content = read_file(sys.argv[1])
print(content)Error messages go to sys.stderr so they appear even when the user redirects output. The script exits with code 1 on any failure, which tells shell scripts and CI that something went wrong.
Common mistakes
Using exit() or quit() instead of sys.exit(). The built-in exit() and quit() exist for interactive use in the REPL. They may not work in all environments, especially frozen or embedded Python. Always use sys.exit() in scripts.
Accessing sys.argv without checking length. sys.argv[1] raises IndexError when no arguments are passed. Always check len(sys.argv) before accessing indices.
Modifying sys.path as a permanent solution. Adding directories to sys.path at runtime is a temporary fix. For reusable code, structure your project as a proper package or set PYTHONPATH in your shell profile.
Rune AI
Key Insights
- Use
sys.argvto read command-line arguments; the first element is always the script name. - Use
sys.exit(code)to terminate a program with an exit status. - Use
sys.stderr.write()for error messages so they are not mixed with standard output. sys.pathis the list of directories Python searches for module imports.sys.versionandsys.version_infoprovide the running Python version.- Use
sys.stdin.read()for piped input andsys.stdout.write()for programmatic output.
Frequently Asked Questions
What is the difference between sys.exit() and exit()?
How do I add a directory to the Python import path at runtime?
What is sys.platform and when should I use it?
Conclusion
The sys module gives you access to the Python interpreter's runtime state. Use sys.argv for command-line arguments, sys.exit() to terminate with a status code, sys.stdin/sys.stdout/sys.stderr for I/O streams, and sys.path to understand or modify the module search path. For parsing complex command-line arguments, prefer argparse over raw sys.argv.
More in this topic
Format Dates and Times in Python
Learn how to use strftime and strptime to format dates as strings and parse date strings into Python datetime objects.
What Is the Python Standard Library?
Learn what the Python standard library is, why it matters, and how to use its built-in modules without installing anything extra.
Encode and Decode Base64 Data in Python
Learn how to use Python's base64 module to encode binary data as text and decode Base64 strings back to bytes.