Movatterモバイル変換


[0]ホーム

URL:


[Python-Dev] Second round: arbitrary function and method attributes

Barry A. Warsawbwarsaw@cnri.reston.va.us
Tue, 11 Apr 2000 19:22:14 -0400 (EDT)


--HXjrLbAr5vContent-Type: text/plain; charset=us-asciiContent-Description: message body textContent-Transfer-Encoding: 7bitHere's the second go at adding arbitrary attribute support to functionand method objects.  Note that this time it's illegal (TypeError) toset an attribute on a bound method object; getting an attribute on abound method object returns the value on the underlying functionobject.  First the diffs, then the test case and test output.Enjoy,-Barry--HXjrLbAr5vContent-Type: text/plainContent-Description: Diff -u to add arbitrary attrs to funcs and methsContent-Disposition: inline;filename="methdiff.txt"Content-Transfer-Encoding: 7bitIndex: Include/funcobject.h===================================================================RCS file: /projects/cvsroot/python/dist/src/Include/funcobject.h,vretrieving revision 2.16diff -u -r2.16 funcobject.h--- funcobject.h1998/12/04 18:48:022.16+++ funcobject.h2000/04/07 21:30:40@@ -44,6 +44,7 @@ PyObject *func_defaults; PyObject *func_doc; PyObject *func_name;+PyObject *func_dict; } PyFunctionObject;  extern DL_IMPORT(PyTypeObject) PyFunction_Type;Index: Objects/classobject.c===================================================================RCS file: /projects/cvsroot/python/dist/src/Objects/classobject.c,vretrieving revision 2.84diff -u -r2.84 classobject.c--- classobject.c2000/04/10 13:03:192.84+++ classobject.c2000/04/11 22:05:08@@ -1550,28 +1550,75 @@ /* Dummies that are not handled by getattr() except for __members__ */ {"__doc__",T_INT,0}, {"__name__",T_INT,0},+{"__dict__",    T_INT,          0}, {NULL}/* Sentinel */ }; +static int+instancemethod_setattro(im, name, v)+register PyMethodObject *im;+PyObject *name;+PyObject *v;+{+char* sname = PyString_AsString(name);+if (sname == NULL)+return -1;++if (PyEval_GetRestricted() ||+    strcmp(sname, "im_func") == 0 ||+    strcmp(sname, "im_self") == 0 ||+    strcmp(sname, "im_class") == 0)+{+       PyErr_Format(PyExc_TypeError, "read-only attribute: %s", sname);+       return -1;+}+if (im->im_self != NULL) {+PyErr_Format(PyExc_TypeError,+     "cannot set bound instance-method attribute: %s",+     sname);+return -1;+}+return PyObject_SetAttr(im->im_func, name, v);+}++ static PyObject *-instancemethod_getattr(im, name)+instancemethod_getattro(im, name) register PyMethodObject *im; PyObject *name; {-char *sname = PyString_AsString(name);+PyObject *rtn;+char* sname = PyString_AsString(name);++if (sname == NULL)+return NULL;+ if (sname[0] == '_') { /* Inherit __name__ and __doc__ from the callable object-   implementing the method */-        if (strcmp(sname, "__name__") == 0 ||-    strcmp(sname, "__doc__") == 0)+   implementing the method.  Can't allow access to __dict__+   here because it should not be readable in restricted+   execution mode.+*/+if (strcmp(sname, "__name__") == 0 ||+    strcmp(sname, "__doc__") == 0) { return PyObject_GetAttr(im->im_func, name);+} } if (PyEval_GetRestricted()) {-PyErr_SetString(PyExc_RuntimeError,-    "instance-method attributes not accessible in restricted mode");+PyErr_Format(PyExc_RuntimeError,+    "instance-method attributes not accessible in restricted mode: %s",+     sname); return NULL;+}+if (sname[0] == '_' && strcmp(sname, "__dict__") == 0)+return PyObject_GetAttr(im->im_func, name);++rtn = PyMember_Get((char *)im, instancemethod_memberlist, sname);+if (rtn == NULL) {+PyErr_Clear();+rtn = PyObject_GetAttr(im->im_func, name); }-return PyMember_Get((char *)im, instancemethod_memberlist, sname);+return rtn; }  static void@@ -1672,8 +1719,8 @@ (hashfunc)instancemethod_hash, /*tp_hash*/ 0,/*tp_call*/ 0,/*tp_str*/-(getattrofunc)instancemethod_getattr, /*tp_getattro*/-0,/*tp_setattro*/+(getattrofunc)instancemethod_getattro, /*tp_getattro*/+(setattrofunc)instancemethod_setattro, /*tp_setattro*/ };  /* Clear out the free list */Index: Objects/funcobject.c===================================================================RCS file: /projects/cvsroot/python/dist/src/Objects/funcobject.c,vretrieving revision 2.18diff -u -r2.18 funcobject.c--- funcobject.c1998/05/22 00:55:342.18+++ funcobject.c2000/04/11 22:06:12@@ -62,6 +62,7 @@ doc = Py_None; Py_INCREF(doc); op->func_doc = doc;+op->func_dict = PyDict_New(); } return (PyObject *)op; }@@ -133,6 +134,8 @@ {"__name__",T_OBJECT,OFF(func_name),READONLY}, {"func_defaults",T_OBJECT,OFF(func_defaults)}, {"func_doc",T_OBJECT,OFF(func_doc)},+{"func_dict",   T_OBJECT,       OFF(func_dict)},+{"__dict__",    T_OBJECT,       OFF(func_dict)}, {"__doc__",T_OBJECT,OFF(func_doc)}, {NULL}/* Sentinel */ };@@ -142,12 +145,21 @@ PyFunctionObject *op; char *name; {+PyObject* rtn;+ if (name[0] != '_' && PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError,   "function attributes not accessible in restricted mode"); return NULL;+}+rtn = PyMember_Get((char *)op, func_memberlist, name);+if (rtn == NULL) {+PyErr_Clear();+rtn = PyMapping_GetItemString(op->func_dict, name);+if (rtn == NULL)+PyErr_SetString(PyExc_AttributeError, name); }-return PyMember_Get((char *)op, func_memberlist, name);+return rtn; }  static int@@ -156,6 +168,8 @@ char *name; PyObject *value; {+int rtn;+ if (PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError,   "function attributes not settable in restricted mode");@@ -178,8 +192,23 @@ } if (value == Py_None) value = NULL;+}+else if (strcmp(name, "func_dict") == 0 ||+ strcmp(name, "__dict__") == 0)+{+if (value == NULL || !PyMapping_Check(value)) {+PyErr_SetString(+PyExc_TypeError,+"must set func_dict to a mapping object");+return -1;+}+}+rtn = PyMember_Set((char *)op, func_memberlist, name, value);+if (rtn < 0) {+PyErr_Clear();+rtn = PyMapping_SetItemString(op->func_dict, name, value); }-return PyMember_Set((char *)op, func_memberlist, name, value);+return rtn; }  static void@@ -191,6 +220,7 @@ Py_DECREF(op->func_name); Py_XDECREF(op->func_defaults); Py_XDECREF(op->func_doc);+Py_XDECREF(op->func_dict); PyMem_DEL(op); } --HXjrLbAr5vContent-Type: text/plainContent-Description: Test of func/meth attrsContent-Disposition: inline;filename="test_funcattrs.py"Content-Transfer-Encoding: 7bitfrom test_support import verboseclass F:    def a(self):        passdef b():    pass# setting attributes on functionstry:    b.blahexcept AttributeError:    passelse:    print 'did not get expected AttributeError'b.blah = 1print b.blah == 1print 'blah' in dir(b)# setting attributes on unbound methodstry:    F.a.blahexcept AttributeError:    passelse:    print 'did not get expected AttributeError'F.a.blah = 1print F.a.blah == 1print 'blah' in dir(F.a)# setting attributes on bound methods is illegalf1 = F()try:    f1.a.snerp = 1except TypeError:    passelse:    print 'did not get expected TypeError'# but accessing attributes on bound methods is fineprint f1.a.blahprint 'blah' in dir(f1.a)f2 = F()print f1.a.blah == f2.a.blahF.a.wazoo = Ff1.a.wazoo is f2.a.wazoo# try setting __dict__ illegallytry:    F.a.__dict__ = (1, 2, 3)except TypeError:    passelse:    print 'did not get expected TypeError'F.a.__dict__ = {'one': 111, 'two': 222, 'three': 333}print f1.a.two == 222from UserDict import UserDictd = UserDict({'four': 444, 'five': 555})F.a.__dict__ = dtry:    f2.a.twoexcept AttributeError:    passelse:    print 'did not get expected AttributeError'print f2.a.four is f1.a.four is F.a.four--HXjrLbAr5vContent-Type: text/plainContent-Description: Output of test of func/meth attrsContent-Disposition: inline;filename="test_funcattrs"Content-Transfer-Encoding: 7bittest_funcattrs111111111--HXjrLbAr5v--


[8]ページ先頭

©2009-2025 Movatter.jp