Add PEP 3121.
This commit is contained in:
parent
fe42ad186f
commit
e4acda0af6
|
@ -118,6 +118,7 @@ Index by Category
|
|||
S 3118 Revising the buffer protocol Oliphant, Banks
|
||||
S 3119 Introducing Abstract Base Classes GvR, Talin
|
||||
S 3120 Using UTF-8 as the default source encoding von Löwis
|
||||
S 3121 Module Initialization and finalization von Löwis
|
||||
S 3141 A Type Hierarchy for Numbers Yasskin
|
||||
|
||||
Finished PEPs (done, implemented in Subversion)
|
||||
|
@ -476,6 +477,7 @@ Numerical Index
|
|||
S 3118 Revising the buffer protocol Oliphant, Banks
|
||||
S 3119 Introducing Abstract Base Classes GvR, Talin
|
||||
S 3120 Using UTF-8 as the default source encoding von Löwis
|
||||
S 3121 Module Initialization and finalization von Löwis
|
||||
S 3141 A Type Hierarchy for Numbers Yasskin
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
PEP: 3121
|
||||
Title: Module Initialization and finalization
|
||||
Version: $Revision: 54994 $
|
||||
Last-Modified: $Date: 2007-04-27 08:34:37 +0200 (Fr, 27 Apr 2007) $
|
||||
Author: Martin v. Löwis <martin@v.loewis.de>
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 27-Apr-2007
|
||||
Python-Version: 3.0
|
||||
Post-History:
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
Module initialization currently has a few deficiencies. There is no
|
||||
cleanup for modules, the entry point name might give naming conflicts,
|
||||
the entry functions don't follow the usual calling convention, and
|
||||
multiple interpreters are not supported well. This PEP addresses these
|
||||
issues.
|
||||
|
||||
Module Finalization
|
||||
===================
|
||||
|
||||
Currently, C modules are initialized usually once and then "live"
|
||||
forever. The only exception is when Py_Finalize() is called: then
|
||||
the initialization routine is invoked a second time. This is bad
|
||||
from a resource management point of view: memory and other resources
|
||||
might get allocated each time initialization is called, but there
|
||||
is no way to reclaim them. As a result, there is currently no
|
||||
way to completely release all resources Python has allocated.
|
||||
|
||||
Entry point name conflicts
|
||||
==========================
|
||||
|
||||
The entry point is currently called init<module>. This might conflict
|
||||
with other symbols also called init<something>. In particular,
|
||||
initsocket is known to have conflicted in the past (this specific
|
||||
problem got resolved as a side effect of renaming the module to
|
||||
_socket).
|
||||
|
||||
Entry point signature
|
||||
=====================
|
||||
|
||||
The entry point is currently a procedure (returning void). This
|
||||
deviates from the usual calling conventions; callers can find out
|
||||
whether there was an error during initialization only by checking
|
||||
PyErr_Occurred. The entry point should return a PyObject*, which will
|
||||
be the module created, or NULL in case of an exception.
|
||||
|
||||
Multiple Interpreters
|
||||
=====================
|
||||
|
||||
Currently, extension modules share their state across all
|
||||
interpreters. This allows for undesirable information leakage across
|
||||
interpreters: one script could permanently corrupt objects in an
|
||||
extension module, possibly breaking all scripts in other interpreters.
|
||||
|
||||
Specification
|
||||
=============
|
||||
|
||||
The module initialization routines change their signature
|
||||
to::
|
||||
|
||||
PyObject *PyInit_<modulename>()
|
||||
|
||||
The initialization routine will be invoked once per
|
||||
interpreter, when the module is imported. It should
|
||||
return a new module object each time.
|
||||
|
||||
In order to store per-module state in C variables,
|
||||
each module object will contain a block of memory
|
||||
that is interpreted only by the module. The amount
|
||||
of memory used for the module is specified at
|
||||
the point of creation of the module.
|
||||
|
||||
In addition to the initialization function, a module
|
||||
may implement a number of additional callback
|
||||
function, which are invoked when the module's
|
||||
tp_traverse, tp_clear, and tp_free functions are
|
||||
invoked, and when the module is reloaded.
|
||||
|
||||
The entire module definition is combined in a struct
|
||||
PyModuleDef::
|
||||
|
||||
struct PyModuleDef{
|
||||
PyModuleDef_Base m_base; /* To be filled out by the interpreter */
|
||||
Py_ssize_t m_size; /* Size of per-module data */
|
||||
PyMethodDef *m_methods;
|
||||
inquiry m_reload;
|
||||
traverseproc m_traverse;
|
||||
inquiry m_clear;
|
||||
freefunc m_free;
|
||||
};
|
||||
|
||||
Creation of a module is changed to expect an optional
|
||||
PyModuleDef*. The module state will be
|
||||
null-initialized.
|
||||
|
||||
Each module method with be passed the module object
|
||||
as the first parameter. To access the module data,
|
||||
a function::
|
||||
|
||||
void* PyModule_GetData(PyObject*);
|
||||
|
||||
will be provided. In addition, to lookup a module
|
||||
more efficiently than going through sys.modules,
|
||||
a function::
|
||||
|
||||
PyObject* PyState_FindModule(struct PyModuleDef*);
|
||||
|
||||
will be provided. This lookup function will use an
|
||||
index located in the m_base field, to find the
|
||||
module by index, not by name.
|
||||
|
||||
As all Python objects should be controlled through
|
||||
the Python memory management, usage of "static"
|
||||
type objects is discouraged, unless the type object
|
||||
itself has no memory-managed state. To simplify
|
||||
definition of heap types, a new method::
|
||||
|
||||
PyTypeObject* PyType_Copy(PyTypeObject*);
|
||||
|
||||
is added.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
xxmodule.c would be changed to remove the initxx
|
||||
function, and add the following code instead::
|
||||
|
||||
struct xxstate{
|
||||
PyObject *ErrorObject;
|
||||
PyObject *Xxo_Type;
|
||||
};
|
||||
|
||||
#define xxstate(o) ((struct xxstate*)PyModule_GetState(o))
|
||||
|
||||
static int xx_traverse(PyObject *m, visitproc v,
|
||||
void *arg)
|
||||
{
|
||||
Py_VISIT(xxstate(m)->ErrorObject);
|
||||
Py_VISIT(xxstate(m)->Xxo_Type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xx_clear(PyObject *m)
|
||||
{
|
||||
Py_CLEAR(xxstate(m)->ErrorObject);
|
||||
Py_CLEAR(xxstate(m)->Xxo_Type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct PyModuleDef xxmodule = {
|
||||
{}, /* m_base */
|
||||
sizeof(struct xxstate),
|
||||
&xx_methods,
|
||||
0, /* m_reload */
|
||||
xx_traverse,
|
||||
xx_clear,
|
||||
0, /* m_free - not needed, since all is done in m_clear */
|
||||
}
|
||||
|
||||
PyObject*
|
||||
PyInit_xx()
|
||||
{
|
||||
PyObject *res = PyModule_New("xx", &xxmodule);
|
||||
if (!res) return NULL;
|
||||
xxstate(res)->ErrorObject = PyErr_NewException("xx.error, NULL, NULL);
|
||||
if (!xxstate(res)->ErrorObject) {
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
xxstate(res)->XxoType = PyType_Copy(&Xxo_Type);
|
||||
if (!xxstate(res)->Xxo_Type) {
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Discussion
|
||||
==========
|
||||
|
||||
Tim Peters reports in [1]_ that PythonLabs considered such a feature
|
||||
at one point, and lists the following additional hooks which aren't
|
||||
currently supported in this PEP:
|
||||
|
||||
* when the module object is deleted from sys.modules
|
||||
|
||||
* when Py_Finalize is called
|
||||
|
||||
* when Python exits
|
||||
|
||||
* when the Python DLL is unloaded (Windows only)
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] Tim Peters, reporting earlier conversation about such a feature
|
||||
http://mail.python.org/pipermail/python-3000/2006-April/000726.html
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
||||
|
||||
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
sentence-end-double-space: t
|
||||
fill-column: 70
|
||||
coding: utf-8
|
||||
End:
|
Loading…
Reference in New Issue