[Python-Dev] Arbitrary attributes on funcs and methods
Greg Stein
gstein@lyra.org
Mon, 10 Apr 2000 11:13:08 -0700 (PDT)
On Mon, 10 Apr 2000, Barry Warsaw wrote:
>...
> Below is a very raw set of patches to add an attribute dictionary to
> funcs and methods. It's only been minimally tested, but if y'all like
> the idea,
+1 on concept, -1 on the patch :-)
>...
> P.S. I promised to add a little note about setattr and getattr
> vs. setattro and getattro. There's very little documentation about
> the differences, and searching on python.org doesn't seem to turn up
> anything. The differences are simple. setattr/getattr take a char*
> argument naming the attribute to change, while setattro/getattro take
> a PyObject* (hence the trailing `o' -- for Object). This stuff should
> get documented in the C API, but at least now, it'll turn up in a SIG
> search. :)
And note that the getattro/setattro is preferred. It is easy to extract
the char* from them; the other direction requires construction of an
object.
>...
> + static int
> + instancemethod_setattr(im, name, v)
> + register PyMethodObject *im;
> + char *name;
> + PyObject *v;
IMO, this should be instancemethod_setattro() and take a PyObject *name.
In the function, you can extract the string for comparison.
>...
> + {
> + int rtn;
This variable isn't used.
>...
> static PyObject *
> instancemethod_getattr(im, name)
> register PyMethodObject *im;
> ! char *name;
IMO, this should remain a getattro function. (and fix the name)
In your update, note how many GetAttrString calls there are. The plain
GetAttr is typically faster.
>...
> + rtn = PyMember_Get((char *)im, instancemethod_memberlist, name);
> + if (rtn == NULL) {
> + PyErr_Clear();
> + rtn = PyObject_GetAttrString(im->im_func, name);
> + if (rtn == NULL)
> + PyErr_SetString(PyExc_AttributeError, name);
Why do you mask this second error with the AttributeError? Seems that you
should just leave whatever is there (typically an AttributeError, but
maybe not!).
>...
> --- 144,167 ----
> PyFunctionObject *op;
> char *name;
> {
> + PyObject* rtn;
> +
> if (name[0] != '_' && PyEval_GetRestricted()) {
> PyErr_SetString(PyExc_RuntimeError,
> "function attributes not accessible in restricted mode");
> return NULL;
> + }
> + if (strcmp(name, "__dict__") == 0)
> + return op->func_dict;
This is superfluous. The PyMember_Get will do this.
> + rtn = PyMember_Get((char *)op, func_memberlist, name);
> + if (rtn == NULL) {
> + PyErr_Clear();
> + rtn = PyDict_GetItemString(op->func_dict, name);
> + if (rtn == NULL)
> + PyErr_SetString(PyExc_AttributeError, name);
Again, with the masking...
>...
> + else if (strcmp(name, "func_dict") == 0) {
> + if (value == NULL || !PyDict_Check(value)) {
> + PyErr_SetString(
> + PyExc_TypeError,
> + "func_dict must be set to a dict object");
This raises an interesting thought. Why not just require the mapping
protocol?
Cheers,
-g
--
Greg Stein, http://www.lyra.org/