diff --git a/pep-0573.rst b/pep-0573.rst index 466895166..4ed0abf0b 100644 --- a/pep-0573.rst +++ b/pep-0573.rst @@ -78,13 +78,13 @@ Rationale PEP 489 introduced a new way to initialize extension modules, which brings several advantages to extensions that implement it: - * The extension modules behave more like their Python counterparts. - * The extension modules can easily support loading into pre-existing - module objects, which paves the way for extension module support for - ``runpy`` or for systems that enable extension module reloading. - * Loading multiple modules from the same extension is possible, which - makes testing module isolation (a key feature for proper sub-interpreter - support) possible from a single interpreter. +* The extension modules behave more like their Python counterparts. +* The extension modules can easily support loading into pre-existing + module objects, which paves the way for extension module support for + ``runpy`` or for systems that enable extension module reloading. +* Loading multiple modules from the same extension is possible, which + makes testing module isolation (a key feature for proper sub-interpreter + support) possible from a single interpreter. The biggest hurdle for adoption of PEP 489 is allowing access to module state from methods of extension types. @@ -143,11 +143,11 @@ Background The implementation of a Python method may need access to one or more of the following pieces of information: - * The instance it is called on (``self``) - * The underlying function - * The class the method was defined in - * The corresponding module - * The module state +* The instance it is called on (``self``) +* The underlying function +* The class the method was defined in +* The corresponding module +* The module state In Python code, the Python-level equivalents may be retrieved as:: @@ -178,14 +178,14 @@ This means that they only have access to their arguments and C level thread-loca and process-global states. Traditionally, many extension modules have stored their shared state in C-level process globals, causing problems when: - * running multiple initialize/finalize cycles in the same process - * reloading modules (e.g. to test conditional imports) - * loading extension modules in subinterpreters +* running multiple initialize/finalize cycles in the same process +* reloading modules (e.g. to test conditional imports) +* loading extension modules in subinterpreters PEP 3121 attempted to resolve this by offering the ``PyState_FindModule`` API, but this still has significant problems when it comes to extension methods (rather than module level functions): - * it is markedly slower than directly accessing C-level process-global state - * there is still some inherent reliance on process global state that means it still doesn't reliably handle module reloading +* it is markedly slower than directly accessing C-level process-global state +* there is still some inherent reliance on process global state that means it still doesn't reliably handle module reloading It's also the case that when looking up a C-level struct such as module state, supplying an unexpected object layout can crash the interpreter, so it's significantly more important to ensure that extension @@ -205,13 +205,13 @@ The additional module level context described above can be made available with t Both additions are optional; extension authors need to opt in to start using them: - * Add a pointer to the module to heap type objects. +* Add a pointer to the module to heap type objects. - * Pass the defining class to the underlying C function. +* Pass the defining class to the underlying C function. - The defining class is readily available at the time built-in - method object (``PyCFunctionObject``) is created, so it can be stored - in a new struct that extends ``PyCFunctionObject``. + The defining class is readily available at the time built-in + method object (``PyCFunctionObject``) is created, so it can be stored + in a new struct that extends ``PyCFunctionObject``. The module state can then be retrieved from the module object via ``PyModule_GetState``. @@ -233,12 +233,12 @@ The problem with slot methods is that their C API is fixed, so we can't simply add a new argument to pass in the defining class. Two possible solutions have been proposed to this problem: - * Look up the class through walking the MRO. - This is potentially expensive, but will be useful if performance is not - a problem (such as when raising a module-level exception). - * Storing a pointer to the defining class of each slot in a separate table, - ``__typeslots__`` [#typeslots-mail]_. This is technically feasible and fast, - but quite invasive. +* Look up the class through walking the MRO. + This is potentially expensive, but will be useful if performance is not + a problem (such as when raising a module-level exception). +* Storing a pointer to the defining class of each slot in a separate table, + ``__typeslots__`` [#typeslots-mail]_. This is technically feasible and fast, + but quite invasive. Due to the invasiveness of the latter approach, this PEP proposes adding an MRO walking helper for use in slot method implementations, deferring the more complex alternative