From 5e897959db37752da4c6b476903cdc5e1357093c Mon Sep 17 00:00:00 2001 From: "Michael W. Hudson" Date: Thu, 12 Aug 2004 18:12:44 +0000 Subject: 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. --- Doc/lib/libstdtypes.tex | 21 ++------------ Doc/ref/ref3.tex | 71 ++++++++++++++++++++++++++++++++-------------- Lib/test/test_funcattrs.py | 11 +++++-- Misc/NEWS | 3 ++ Objects/funcobject.c | 36 ++++++++++++++++++++--- 5 files changed, 95 insertions(+), 47 deletions(-) diff --git a/Doc/lib/libstdtypes.tex b/Doc/lib/libstdtypes.tex index 01e800a..e97009e 100644 --- a/Doc/lib/libstdtypes.tex +++ b/Doc/lib/libstdtypes.tex @@ -1682,25 +1682,8 @@ and user-defined functions. Both support the same operation (to call the function), but the implementation is different, hence the different object types. -The implementation adds two special read-only attributes: -\code{\var{f}.func_code} is a function's \dfn{code -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. +See the \citetitle[../ref/ref.html]{Python Reference Manual} for more +information. \subsubsection{Methods \label{typesmethods}} \obindex{method} diff --git a/Doc/ref/ref3.tex b/Doc/ref/ref3.tex index 7f337f6..973275f 100644 --- a/Doc/ref/ref3.tex +++ b/Doc/ref/ref3.tex @@ -433,28 +433,55 @@ parameter list. \obindex{function} \obindex{user-defined function} -Special attributes: \member{func_doc} or \member{__doc__} is the -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}, -\member{func_doc}/\member{__doc__}, and -\member{func_dict}/\member{__dict__} may be writable; the -others can never be changed. Additional information about a -function's definition can be retrieved from its code object; see the -description of internal types below. +Special attributes: + +\begin{tableiii}{lll}{member}{Attribute}{Meaning}{} + \lineiii{func_doc}{The function's documentation string, or + \code{None} if unavailable}{Writable} + + \lineiii{__doc__}{Another way of spelling + \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)}{ \ttindex{func_doc} diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py index 2c31d36..3ccb263 100644 --- a/Lib/test/test_funcattrs.py +++ b/Lib/test/test_funcattrs.py @@ -268,8 +268,15 @@ def test_func_name(): def f(): pass verify(f.__name__ == "f") verify(f.func_name == "f") - cantset(f, "func_name", "f") - cantset(f, "__name__", "f") + f.__name__ = "g" + 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 f(): pass diff --git a/Misc/NEWS b/Misc/NEWS index 15d73e1..f6e2faf 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 2.4 alpha 3? 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 carefully that passing them on to PyCode_New() won't trigger calls to Py_FatalError() or PyErr_BadInternalCall(). It is still the case diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 971eb1c..c46887c 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -163,8 +163,6 @@ static PyMemberDef func_memberlist[] = { {"__doc__", T_OBJECT, OFF(func_doc), WRITE_RESTRICTED}, {"func_globals", T_OBJECT, OFF(func_globals), 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}, {NULL} /* Sentinel */ }; @@ -250,6 +248,36 @@ func_set_code(PyFunctionObject *op, PyObject *value) } 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 * func_get_defaults(PyFunctionObject *op) { if (restricted()) @@ -291,6 +319,8 @@ static PyGetSetDef func_getsetlist[] = { (setter)func_set_defaults}, {"func_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 */ }; @@ -416,8 +446,6 @@ func_dealloc(PyFunctionObject *op) static PyObject* func_repr(PyFunctionObject *op) { - if (op->func_name == Py_None) - return PyString_FromFormat("", op); return PyString_FromFormat("", PyString_AsString(op->func_name), op); -- cgit v0.12