This is my patch

[ 1004703 ] Make func_name writable

plus fixing a couple of nits in the documentation changes spotted by MvL
and a Misc/NEWS entry.
This commit is contained in:
Michael W. Hudson 2004-08-12 18:12:44 +00:00
parent 5523c2517f
commit 5e897959db
5 changed files with 94 additions and 46 deletions

View File

@ -1682,25 +1682,8 @@ and user-defined functions. Both support the same operation (to call
the function), but the implementation is different, hence the the function), but the implementation is different, hence the
different object types. different object types.
The implementation adds two special read-only attributes: See the \citetitle[../ref/ref.html]{Python Reference Manual} for more
\code{\var{f}.func_code} is a function's \dfn{code information.
object}\obindex{code} (see below) and \code{\var{f}.func_globals} is
the dictionary used as the function's global namespace (this is the
same as \code{\var{m}.__dict__} where \var{m} is the module in which
the function \var{f} was defined).
Function objects also support getting and setting arbitrary
attributes, which can be used, for example, to attach metadata to
functions. Regular attribute dot-notation is used to get and set such
attributes. \emph{Note that the current implementation only supports
function attributes on user-defined functions. Function attributes on
built-in functions may be supported in the future.}
Functions have another special attribute \code{\var{f}.__dict__}
(a.k.a. \code{\var{f}.func_dict}) which contains the namespace used to
support function attributes. \code{__dict__} and \code{func_dict} can
be accessed directly or set to a dictionary object. A function's
dictionary cannot be deleted.
\subsubsection{Methods \label{typesmethods}} \subsubsection{Methods \label{typesmethods}}
\obindex{method} \obindex{method}

View File

@ -433,28 +433,55 @@ parameter list.
\obindex{function} \obindex{function}
\obindex{user-defined function} \obindex{user-defined function}
Special attributes: \member{func_doc} or \member{__doc__} is the Special attributes:
function's documentation string, or \code{None} if unavailable;
\member{func_name} or \member{__name__} is the function's name;
\member{__module__} is the name of the module the function was defined
in, or \code{None} if unavailable;
\member{func_defaults} is a tuple containing default argument values for
those arguments that have defaults, or \code{None} if no arguments
have a default value; \member{func_code} is the code object representing
the compiled function body; \member{func_globals} is (a reference to)
the dictionary that holds the function's global variables --- it
defines the global namespace of the module in which the function was
defined; \member{func_dict} or \member{__dict__} contains the
namespace supporting arbitrary function attributes;
\member{func_closure} is \code{None} or a tuple of cells that contain
bindings for the function's free variables.
Of these, \member{func_code}, \member{func_defaults}, \begin{tableiii}{lll}{member}{Attribute}{Meaning}{}
\member{func_doc}/\member{__doc__}, and \lineiii{func_doc}{The function's documentation string, or
\member{func_dict}/\member{__dict__} may be writable; the \code{None} if unavailable}{Writable}
others can never be changed. Additional information about a
function's definition can be retrieved from its code object; see the \lineiii{__doc__}{Another way of spelling
description of internal types below. \member{func_doc}}{Writable}
\lineiii{func_name}{The function's name}{Writable}
\lineiii{__name__}{Another way of spelling
\member{func_name}}{Writable}
\lineiii{__module__}{The name of the module the function was defined
in, or \code{None} if unavailable.}{Writable}
\lineiii{func_defaults}{Atuple containing default argument values
for those arguments that have defaults, or \code{None} if no
arguments have a default value}{Writable}
\lineiii{func_code}{The code object representing the compiled
function body.}{Writable}
\lineiii{func_globals}{A reference to the dictionary that holds the
function's global variables --- the global namespace of the module
in which the function was defined.}{Read-only}
\lineiii{func_dict}{The namespace supporting arbitrary function
attributes.}{Writable}
\lineiii{func_closure}{\code{None} or a tuple of cells that contain
bindings for the function's free variables.}{Read-only}
\end{tableiii}
Most of the attributes labelled ``Writable'' check the type of the
assigned value.
\versionchanged[\code{func_name} is now writable]{2.4}
Function objects also support getting and setting arbitrary
attributes, which can be used, for example, to attach metadata to
functions. Regular attribute dot-notation is used to get and set such
attributes. \emph{Note that the current implementation only supports
function attributes on user-defined functions. Function attributes on
built-in functions may be supported in the future.}
Additional information about a function's definition can be retrieved
from its code object; see the description of internal types below.
\withsubitem{(function attribute)}{ \withsubitem{(function attribute)}{
\ttindex{func_doc} \ttindex{func_doc}

View File

@ -268,8 +268,15 @@ def test_func_name():
def f(): pass def f(): pass
verify(f.__name__ == "f") verify(f.__name__ == "f")
verify(f.func_name == "f") verify(f.func_name == "f")
cantset(f, "func_name", "f") f.__name__ = "g"
cantset(f, "__name__", "f") verify(f.__name__ == "g")
verify(f.func_name == "g")
f.func_name = "h"
verify(f.__name__ == "h")
verify(f.func_name == "h")
cantset(f, "func_globals", 1)
cantset(f, "__name__", 1)
def test_func_code(): def test_func_code():
def f(): pass def f(): pass

View File

@ -12,6 +12,9 @@ What's New in Python 2.4 alpha 3?
Core and builtins Core and builtins
----------------- -----------------
- The ``func_name`` (a.k.a. ``__name__``) attribute of user-defined
functions is now writable.
- code_new (a.k.a new.code()) now checks its arguments sufficiently - code_new (a.k.a new.code()) now checks its arguments sufficiently
carefully that passing them on to PyCode_New() won't trigger calls carefully that passing them on to PyCode_New() won't trigger calls
to Py_FatalError() or PyErr_BadInternalCall(). It is still the case to Py_FatalError() or PyErr_BadInternalCall(). It is still the case

View File

@ -163,8 +163,6 @@ static PyMemberDef func_memberlist[] = {
{"__doc__", T_OBJECT, OFF(func_doc), WRITE_RESTRICTED}, {"__doc__", T_OBJECT, OFF(func_doc), WRITE_RESTRICTED},
{"func_globals", T_OBJECT, OFF(func_globals), {"func_globals", T_OBJECT, OFF(func_globals),
RESTRICTED|READONLY}, RESTRICTED|READONLY},
{"func_name", T_OBJECT, OFF(func_name), READONLY},
{"__name__", T_OBJECT, OFF(func_name), READONLY},
{"__module__", T_OBJECT, OFF(func_module), WRITE_RESTRICTED}, {"__module__", T_OBJECT, OFF(func_module), WRITE_RESTRICTED},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
@ -249,6 +247,36 @@ func_set_code(PyFunctionObject *op, PyObject *value)
return 0; return 0;
} }
static PyObject *
func_get_name(PyFunctionObject *op)
{
if (restricted())
return NULL;
Py_INCREF(op->func_name);
return op->func_name;
}
static int
func_set_name(PyFunctionObject *op, PyObject *value)
{
PyObject *tmp;
if (restricted())
return -1;
/* Not legal to del f.func_name or to set it to anything
* other than a string object. */
if (value == NULL || !PyString_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"func_name must be set to a string object");
return -1;
}
tmp = op->func_name;
Py_INCREF(value);
op->func_name = value;
Py_DECREF(tmp);
return 0;
}
static PyObject * static PyObject *
func_get_defaults(PyFunctionObject *op) func_get_defaults(PyFunctionObject *op)
{ {
@ -291,6 +319,8 @@ static PyGetSetDef func_getsetlist[] = {
(setter)func_set_defaults}, (setter)func_set_defaults},
{"func_dict", (getter)func_get_dict, (setter)func_set_dict}, {"func_dict", (getter)func_get_dict, (setter)func_set_dict},
{"__dict__", (getter)func_get_dict, (setter)func_set_dict}, {"__dict__", (getter)func_get_dict, (setter)func_set_dict},
{"func_name", (getter)func_get_name, (setter)func_set_name},
{"__name__", (getter)func_get_name, (setter)func_set_name},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
@ -416,8 +446,6 @@ func_dealloc(PyFunctionObject *op)
static PyObject* static PyObject*
func_repr(PyFunctionObject *op) func_repr(PyFunctionObject *op)
{ {
if (op->func_name == Py_None)
return PyString_FromFormat("<anonymous function at %p>", op);
return PyString_FromFormat("<function %s at %p>", return PyString_FromFormat("<function %s at %p>",
PyString_AsString(op->func_name), PyString_AsString(op->func_name),
op); op);