尚未翻译
本页面尚未翻译成中文,因此显示英文原文。 帮助翻译
sysconfig Module Complexity¶
The sysconfig module reports how this Python was built and where it installs things: the
build's configuration variables, and the install schemes whose path templates, such as
{base}/bin, are expanded against them. The configuration variables are loaded on first use and
then cached; install paths are not cached, and every call expands them again from all of
the configuration variables.
V is the configuration variables (on POSIX, everything the build recorded from its Makefile
and pyconfig.h; far fewer on Windows), a is the names passed to get_config_vars(), L is
the lines in a header file handed to parse_config_h(), and D is the #define and #undef
lines among them; header lines are priced as of bounded length. The install-scheme table is a fixed handful of schemes of at most eight paths
each, so scheme and path counts, and the length of one path, are priced as O(1). The first call in
the process to anything that reads configuration variables pays a one-off O(V) load; the bounds
below are for the calls after it. On Python 3.12.8+ and 3.13.1+, a call that finds sys.prefix
changed since the load pays it again, into a new dictionary; from 3.14, so does a changed
sys.exec_prefix.
Complexity Reference¶
Configuration variables¶
| Operation | Time | Space | Notes |
|---|---|---|---|
sysconfig.get_config_vars() |
O(1) | O(1) | Returns the module's cache itself, not a copy |
sysconfig.get_config_vars(*names) |
O(a) | O(a) | A list of values, None for an unknown name |
sysconfig.get_config_var(name) |
O(1) | O(1) | One dict lookup; None for an unknown name |
sysconfig.parse_config_h(fp, vars=None) |
O(L) | O(D) | Reads one line at a time and keeps only the definitions; fills and returns vars when given |
sysconfig.get_makefile_filename() |
O(V) | O(V) | Resolved through get_path() in an installed Python |
sysconfig.get_config_h_filename() |
O(V) | O(V) | Resolved through get_path() in an installed Python |
Install paths¶
| Operation | Time | Space | Notes |
|---|---|---|---|
sysconfig.get_paths(scheme=get_default_scheme(), vars=None, expand=True) |
O(V) | O(V) | Not cached: every call merges all configuration variables into the substitution dict; a vars dict you pass is filled in place |
sysconfig.get_paths(scheme, expand=False) |
O(1) | O(1) | The scheme's own template dict, not a copy |
sysconfig.get_path(name, scheme=get_default_scheme(), vars=None, expand=True) |
O(V) | O(V) | Expands the whole scheme to return one path |
sysconfig.get_path_names() |
O(1) | O(1) | The same tuple on every call |
sysconfig.get_scheme_names() |
O(1) | O(1) | A sorted tuple of the fixed scheme table |
sysconfig.get_default_scheme() |
O(1) | O(1) | 'venv' inside a virtual environment, Python 3.11+ |
sysconfig.get_preferred_scheme(key) |
O(1) | O(1) | key is 'prefix', 'home' or 'user' |
sysconfig._get_preferred_schemes() |
O(1) | O(1) | The hook a redistributor overrides; get_preferred_scheme() reads it |
Platform and build¶
| Operation | Time | Space | Notes |
|---|---|---|---|
sysconfig.get_platform() |
O(1) | O(1) | |
sysconfig.get_python_version() |
O(1) | O(1) | The MAJOR.MINOR string |
sysconfig.is_python_build() |
O(1) | O(1) | At most two file-existence checks |
Configuration Variables¶
Loaded Once, Then Shared¶
The first call loads every configuration variable into one module-level dictionary, and later calls hand back that dictionary itself. Reading a variable is a dict lookup, and the dictionary is the module's own state, not a copy: treat it as read-only.
import sysconfig
config = sysconfig.get_config_vars() # O(V) on the first call, O(1) after
assert sysconfig.get_config_vars() is config # the cache itself, not a copy
suffix = sysconfig.get_config_var('EXT_SUFFIX') # O(1)
assert suffix.endswith(('.so', '.pyd'))
assert sysconfig.get_config_var('NO_SUCH_VARIABLE') is None
version, missing = sysconfig.get_config_vars('py_version_short', 'NO_SUCH_VARIABLE') # O(a)
assert version == sysconfig.get_python_version()
assert missing is None
Parsing a Header¶
parse_config_h() reads its file a line at a time, so memory follows the definitions it keeps,
not the size of the file.
import io
import sysconfig
header = io.StringIO(
"/* pyconfig.h */\n"
"#define HAVE_FORK 1\n"
"#define PY_NAME \"python\"\n"
"/* #undef HAVE_NOTHING */\n"
)
values = sysconfig.parse_config_h(header) # O(L) time, O(D) space
assert values == {'HAVE_FORK': 1, 'PY_NAME': '"python"', 'HAVE_NOTHING': 0}
Install Paths¶
Paths Are Expanded on Every Call¶
get_paths() and get_path() are not cached. Each call merges every configuration variable into
its substitution dictionary before formatting the scheme's paths, so asking for one path costs
the same O(V) as asking for all of them. Fetch the dictionary once and index it.
import sysconfig
paths = sysconfig.get_paths() # O(V) - every call expands the whole scheme
assert set(sysconfig.get_path_names()) <= set(paths)
purelib = paths['purelib'] # O(1) - index the dict you already have
assert purelib == sysconfig.get_path('purelib') # O(V) again, for one path
templates = sysconfig.get_paths(expand=False) # O(1) - the scheme's own templates
assert '{base}' in templates['purelib']
Overriding Variables¶
A vars dictionary replaces the configuration variables it names. It is also the substitution
dictionary itself: every other configuration variable is copied into it, so pass a copy if you
mean to reuse yours.
import os
import sysconfig
overrides = {'base': '/opt/app'}
paths = sysconfig.get_paths(vars=overrides) # O(V)
assert paths['purelib'].startswith(os.path.normpath('/opt/app'))
assert overrides['base'] == '/opt/app' # your value wins...
assert overrides.keys() >= sysconfig.get_config_vars().keys() # ...and every other one was added
Choosing a Scheme¶
import sysconfig
names = sysconfig.get_scheme_names() # O(1) - a fixed table
assert 'posix_prefix' in names and 'nt' in names
assert sysconfig.get_default_scheme() in names # O(1)
assert sysconfig.get_preferred_scheme('home') in names # O(1)
assert set(sysconfig._get_preferred_schemes()) == {'prefix', 'home', 'user'} # O(1)
Platform and Build¶
import sys
import sysconfig
version = sysconfig.get_python_version() # O(1)
assert version == f'{sys.version_info[0]}.{sys.version_info[1]}'
platform = sysconfig.get_platform() # O(1)
if sys.platform == 'win32':
assert platform.startswith('win')
elif sys.platform == 'linux':
assert platform.startswith('linux-')
assert isinstance(sysconfig.is_python_build(), bool) # O(1)
assert sysconfig.get_makefile_filename().endswith('Makefile') # O(V) - goes through get_path()
assert sysconfig.get_config_h_filename().endswith('pyconfig.h') # O(V)
Common Patterns¶
Locating Install Targets¶
import os
import sysconfig
paths = sysconfig.get_paths() # O(V), once
suffix = sysconfig.get_config_var('EXT_SUFFIX') # O(1)
targets = {
name: os.path.join(paths['platlib'], name + suffix) # O(1) per name
for name in ('_speedups', '_parser')
}
assert all(target.startswith(paths['platlib']) for target in targets.values())
Performance Best Practices¶
✅ Do:
- Call
get_paths()once and index the result: eachget_path()call costs as much as the whole dict - Read
get_config_var()freely; after the first call it is a dict lookup - Pass a copy as
varswhen you need your dictionary unchanged
❌ Avoid:
get_path(),get_makefile_filename()orget_config_h_filename()in a loop - each call is O(V)- Mutating what
get_config_vars()orget_paths(expand=False)returns: it is the module's own state, not a copy
Version Notes¶
- Python 3.11+:
get_default_scheme()andget_preferred_scheme('prefix')return'venv'inside a virtual environment - Python 3.11+:
get_config_var('SO')returnsNone; use'EXT_SUFFIX'