diff --git a/peps/pep-0810.rst b/peps/pep-0810.rst index 6d92b3d2ff0..58a635f641d 100644 --- a/peps/pep-0810.rst +++ b/peps/pep-0810.rst @@ -1735,6 +1735,55 @@ Past decisions that violated this principle of keeping core abstractions clean have caused significant pain in the CPython ecosystem, making optimization difficult and introducing subtle bugs. +Transforming lazy objects via ``__class__`` mutation +---------------------------------------------------- + +An alternative implementation approach was proposed where lazy import objects +would be transformed into their final form by mutating their internal state, +rather than replacing the object entirely. Under this approach, a lazy object +would be transformed in-place after the actual import completes. + +This approach was rejected for several reasons: + +1. This technique could potentially work for module objects, but breaks down + completely for arbitrary objects imported via ``from`` statements. When a + user writes ``lazy from foo import bar``, the object ``bar`` could be any + Python object (a function, class, constant, etc.), not just a module. Any + transformation approach would require that the lazy proxy object have + compatible memory layout and other considerations with the target object, + which is impossible to know before loading the module. This creates a + fundamental asymmetry where ``lazy import x`` and ``lazy from x import y`` + would require completely different implementation strategies, with the latter + still needing the proxy replacement mechanism. + +2. Even for module objects, the approach has fundamental limitations. Some + implementations substitute custom classes in ``sys.modules`` that inherit + from or replace the standard module type. These custom module classes can + have different memory layouts and sizes than ``PyModuleObject``. The + transformation approach cannot work with such generic custom module + implementations, creating fragility and maintenance burden across the + ecosystem. + +3. While the transformation approach might appear simpler in some respects, this + is somewhat subjective. It introduces a bifurcated implementation: one path + for modules and a completely different path for non-module objects. Whether + this is simpler than a unified proxy mechanism depends on perspective and + implementation details. + +4. Any code holding a reference to the object before transformation will see a + different type after transformation. This can break code that checks object + types or relies on type stability, particularly C extensions that cache type + pointers or use ``PyObject_TypeCheck``. The transformation also requires + careful coordination between the lazy import machinery and the type system to + ensure that the object remains valid throughout the transformation process. + The current proxy-based design avoids these issues by maintaining clear + boundaries between the lazy proxy and the actual imported object. + +The current design, which uses object replacement through the ``LazyImportType`` +proxy pattern, provides a consistent mechanism that works uniformly for both +``import`` and ``from ... import`` statements while maintaining cleaner +separation between the lazy import machinery and Python's core object model. + Making ``lazy`` imports find the module without loading it ----------------------------------------------------------