os.RTLD_LAZY
Python loads C extension modules with dlopen(); sys.setdlopenflags() chooses the flags for later imports, and ctypes.CDLL(name, mode=...) takes them per library. The usual reason to touch them: make one extension symbols visible to another with RTLD_GLOBAL. Unix only; the constants do not exist on Windows.
Common call
sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
Returns
None (affects later imports)
Replaces
LD_PRELOAD hacks to share symbols between extensions
Watch out
Restore the old flags afterwards; RTLD_LOCAL is 0 on Linux, so OR-ing it changes nothing
os.RTLD_LAZY / RTLD_NOW / RTLD_GLOBAL / RTLD_LOCAL / RTLD_NODELETE / RTLD_NOLOAD / RTLD_DEEPBIND
→ int
Common patterns
Import an extension with global symbols, then restore
Only the imports inside the try see the changed flags.
import os, sys old = sys.getdlopenflags() sys.setdlopenflags(old | os.RTLD_GLOBAL) try: import some_extension finally: sys.setdlopenflags(old)
Load a library globally with ctypes
Later libraries can resolve symbols against it.
import ctypes, os lib = ctypes.CDLL('libfoo.so', mode=os.RTLD_NOW | os.RTLD_GLOBAL)
Is the library already loaded? (glibc)
RTLD_NOLOAD does not load anything; it fails if the library is not loaded yet.
import ctypes, os try: ctypes.CDLL('libssl.so.3', mode=os.RTLD_NOLOAD) loaded = True except OSError: loaded = False
Examples
1. Unix only
import os
all(hasattr(os, n) == (os.name == 'posix') for n in ('RTLD_LAZY', 'RTLD_NOW', 'RTLD_GLOBAL', 'RTLD_LOCAL'))
Returns
True2. sys.getdlopenflags exists on Unix only
import sys
hasattr(sys, 'getdlopenflags') == (sys.platform != 'win32')
Returns
True3. Combine flags with | (Linux values)
RTLD_NOW, RTLD_GLOBAL = 2, 256
RTLD_NOW | RTLD_GLOBAL
Returns
2584. Remove a flag with & ~
RTLD_NOW, RTLD_GLOBAL = 2, 256
flags = RTLD_NOW | RTLD_GLOBAL
flags & ~RTLD_GLOBAL
Returns
25. All seven Linux values are distinct
linux = {'RTLD_LAZY': 1, 'RTLD_NOW': 2, 'RTLD_NOLOAD': 4, 'RTLD_DEEPBIND': 8, 'RTLD_GLOBAL': 256, 'RTLD_LOCAL': 0, 'RTLD_NODELETE': 4096}
len(set(linux.values()))
Returns
7Pitfalls
1. Expecting RTLD_LOCAL to switch GLOBAL off
On Linux RTLD_LOCAL is 0, so OR-ing it into flags that already contain RTLD_GLOBAL changes nothing. Clear the GLOBAL bit instead.
flags | RTLD_LOCAL
RTLD_NOW, RTLD_GLOBAL, RTLD_LOCAL = 2, 256, 0 flags = RTLD_NOW | RTLD_GLOBAL flags | RTLD_LOCAL
258
flags & ~RTLD_GLOBAL
RTLD_NOW, RTLD_GLOBAL, RTLD_LOCAL = 2, 256, 0 flags = RTLD_NOW | RTLD_GLOBAL (flags & ~RTLD_GLOBAL) | RTLD_LOCAL
2
2. Setting the flags and never restoring them
setdlopenflags is process-wide: every extension imported later is loaded the same way. Save the old value and restore it in finally, the same shape as saving any global setting.
set and forget
settings = {'dlopenflags': 2} settings['dlopenflags'] = 2 | 256 settings['dlopenflags']
258
try / finally
settings = {'dlopenflags': 2} old = settings['dlopenflags'] settings['dlopenflags'] = old | 256 try: pass # import the extension here finally: settings['dlopenflags'] = old settings['dlopenflags']
2
When to use
Use it
- Two C extensions that must share symbols (RTLD_GLOBAL)
- Loading shared libraries with ctypes in a specific mode
- Failing early on missing symbols with RTLD_NOW
Reach for something else
- Windows → there is no dlopen; ctypes.WinDLL / CDLL use LoadLibrary (winmode=)
- Ordinary Python code → the default flags are right
Notes
CPython impl
sys.setdlopenflags(flags) / sys.getdlopenflags() store the flags used by the import machinery when it dlopen()s an extension module; on our Linux check the default was 2 (RTLD_NOW)
Availability
Unix only; on our Linux check all seven constants exist, on Windows none do. See the dlopen(3) manual page for the exact meaning; NODELETE, NOLOAD and DEEPBIND are extensions beyond POSIX, so not every Unix defines them
Linux values
RTLD_LOCAL 0, RTLD_LAZY 1, RTLD_NOW 2, RTLD_NOLOAD 4, RTLD_DEEPBIND 8, RTLD_GLOBAL 256, RTLD_NODELETE 4096
ctypes
ctypes.RTLD_GLOBAL and ctypes.RTLD_LOCAL mirror these (256 and 0 on Linux; both 0 on Windows), so ctypes code can use them without importing os constants that Windows lacks
FAQ
The RTLD_* constants, sys.setdlopenflags and sys.getdlopenflags exist only on Unix, and changing the flags affects every later import in the process. The examples show the bit arithmetic with the values from Linux.