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/