Commit 89e79562 authored by Michael W. Hudson's avatar Michael W. Hudson

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.
parent 8080db5a
...@@ -1682,25 +1682,8 @@ and user-defined functions. Both support the same operation (to call ...@@ -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}
......
...@@ -433,28 +433,55 @@ parameter list. ...@@ -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; \begin{tableiii}{lll}{member}{Attribute}{Meaning}{}
\member{__module__} is the name of the module the function was defined \lineiii{func_doc}{The function's documentation string, or
in, or \code{None} if unavailable; \code{None} if unavailable}{Writable}
\member{func_defaults} is a tuple containing default argument values for
those arguments that have defaults, or \code{None} if no arguments \lineiii{__doc__}{Another way of spelling
have a default value; \member{func_code} is the code object representing \member{func_doc}}{Writable}
the compiled function body; \member{func_globals} is (a reference to)
the dictionary that holds the function's global variables --- it \lineiii{func_name}{The function's name}{Writable}
defines the global namespace of the module in which the function was
defined; \member{func_dict} or \member{__dict__} contains the \lineiii{__name__}{Another way of spelling
namespace supporting arbitrary function attributes; \member{func_name}}{Writable}
\member{func_closure} is \code{None} or a tuple of cells that contain
bindings for the function's free variables. \lineiii{__module__}{The name of the module the function was defined
in, or \code{None} if unavailable.}{Writable}
Of these, \member{func_code}, \member{func_defaults},
\member{func_doc}/\member{__doc__}, and \lineiii{func_defaults}{Atuple containing default argument values
\member{func_dict}/\member{__dict__} may be writable; the for those arguments that have defaults, or \code{None} if no
others can never be changed. Additional information about a arguments have a default value}{Writable}
function's definition can be retrieved from its code object; see the
description of internal types below. \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}
......
...@@ -268,8 +268,15 @@ def test_func_name(): ...@@ -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
......
...@@ -12,6 +12,9 @@ What's New in Python 2.4 alpha 3? ...@@ -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
......
...@@ -163,8 +163,6 @@ static PyMemberDef func_memberlist[] = { ...@@ -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) ...@@ -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[] = { ...@@ -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) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment