[Python-checkins] CVS: python/dist/src/Objects classobject.c,2.146,2.147

Guido van Rossum gvanrossum@users.sourceforge.net
Mon, 17 Sep 2001 20:53:26 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv21442

Modified Files:
	classobject.c 
Log Message:
Redo the PyMethod attributes using a dir()-friendly approach, creating
descriptors for each attribute.  The getattr() implementation is
similar to PyObject_GenericGetAttr(), but delegates to im_self instead
of looking in __dict__; I couldn't do this as a wrapper around
PyObject_GenericGetAttr().

XXX A problem here is that this is a case of *delegation*.  dir()
doesn't see exactly the same attributes that are actually defined;
e.g. if the delegate is a Python function object, it supports
attributes like func_code etc., but these are not visible to dir(); on
the other hand, dynamic function attributes (stored in the function's
__dict__) *are* visible to dir().  Maybe we need a mechanism to tell
dir() about the delegation mechanism?  I vaguely recall seeing a
request in the newsgroup for a more formal definition of attribute
delegation too.  Sigh, time for a new PEP.


Index: classobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/classobject.c,v
retrieving revision 2.146
retrieving revision 2.147
diff -C2 -d -r2.146 -r2.147
*** classobject.c	2001/09/08 04:00:12	2.146
--- classobject.c	2001/09/18 03:53:24	2.147
***************
*** 2001,2056 ****
  }
  
! /* Class method methods */
  
  #define OFF(x) offsetof(PyMethodObject, x)
  
  static struct memberlist instancemethod_memberlist[] = {
! 	{"im_func",	T_OBJECT,	OFF(im_func)},
! 	{"im_self",	T_OBJECT,	OFF(im_self)},
! 	{"im_class",	T_OBJECT,	OFF(im_class)},
! 	/* Dummies that are not handled by getattr() except for __members__ */
! 	{"__doc__",	T_INT,		0},
! 	{"__name__",	T_INT,		0},
! 	{"__dict__",    T_OBJECT,       0},
  	{NULL}	/* Sentinel */
  };
  
! static int
! instancemethod_setattro(register PyMethodObject *im, PyObject *name,
! 			PyObject *v)
  {
! 	char *sname = PyString_AsString(name);
  
! 	PyErr_Format(PyExc_TypeError, "read-only attribute: %s", sname);
! 	return -1;
  }
-  
  
  static PyObject *
! instancemethod_getattro(register PyMethodObject *im, PyObject *name)
  {
! 	PyObject *rtn;
! 	char *sname = PyString_AsString(name);
! 	if (sname[0] == '_') {
! 		/* Inherit __name__ and __doc__ from the callable object
! 		   implementing the method */
! 	        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");
! 		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_ExceptionMatches(PyExc_AttributeError)) {
  		PyErr_Clear();
! 		rtn = PyObject_GetAttr(im->im_func, name);
  	}
! 	return rtn;
  }
  
--- 2001,2088 ----
  }
  
! /* Descriptors for PyMethod attributes */
! 
! /* im_class, im_func and im_self are stored in the PyMethod object */
  
  #define OFF(x) offsetof(PyMethodObject, x)
  
  static struct memberlist instancemethod_memberlist[] = {
! 	{"im_class",	T_OBJECT,	OFF(im_class),	READONLY|RESTRICTED},
! 	{"im_func",	T_OBJECT,	OFF(im_func),	READONLY|RESTRICTED},
! 	{"im_self",	T_OBJECT,	OFF(im_self),	READONLY|RESTRICTED},
  	{NULL}	/* Sentinel */
  };
  
! /* __dict__, __doc__ and __name__ are retrieved from im_func */
! 
! static PyObject *
! im_get_dict(PyMethodObject *im)
  {
! 	return PyObject_GetAttrString(im->im_func, "__dict__");
! }
  
! static PyObject *
! im_get_doc(PyMethodObject *im)
! {
! 	return PyObject_GetAttrString(im->im_func, "__doc__");
  }
  
  static PyObject *
! im_get_name(PyMethodObject *im)
  {
! 	return PyObject_GetAttrString(im->im_func, "__name__");
! }
! 
! static struct getsetlist instancemethod_getsetlist[] = {
! 	{"__dict__", (getter)im_get_dict},
! 	{"__doc__", (getter)im_get_doc},
! 	{"__name__", (getter)im_get_name},
! 	{NULL}  /* Sentinel */
! };
! 
! /* The getattr() implementation for PyMethod objects is similar to
!    PyObject_GenericGetAttr(), but instead of looking in __dict__ it
!    asks im_self for the attribute.  Then the error handling is a bit
!    different because we want to preserve the exception raised by the
!    delegate, unless we have an alternative from our class. */
! 
! static PyObject *
! instancemethod_getattro(PyObject *obj, PyObject *name)
! {
! 	PyMethodObject *im = (PyMethodObject *)obj;
! 	PyTypeObject *tp = obj->ob_type;
! 	PyObject *descr, *res;
! 	descrgetfunc f;
! 
! 	if (tp->tp_dict == NULL) {
! 		if (PyType_Ready(tp) < 0)
! 			return NULL;
  	}
! 
! 	descr = _PyType_Lookup(tp, name);
! 	f = NULL;
! 	if (descr != NULL) {
! 		f = descr->ob_type->tp_descr_get;
! 		if (f != NULL && PyDescr_IsData(descr))
! 			return f(descr, obj, (PyObject *)obj->ob_type);
  	}
  
! 	res = PyObject_GetAttr(im->im_func, name);
! 	if (res != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError))
! 		return res;
! 
! 	if (f != NULL) {
  		PyErr_Clear();
! 		return f(descr, obj, (PyObject *)obj->ob_type);
  	}
! 
! 	if (descr != NULL) {
! 		PyErr_Clear();
! 		Py_INCREF(descr);
! 		return descr;
! 	}
! 
! 	assert(PyErr_Occurred());
! 	return NULL;
  }
  
***************
*** 2299,2303 ****
  	0,					/* tp_str */
  	(getattrofunc)instancemethod_getattro,	/* tp_getattro */
! 	(setattrofunc)instancemethod_setattro,	/* tp_setattro */
  	0,					/* tp_as_buffer */
  	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
--- 2331,2335 ----
  	0,					/* tp_str */
  	(getattrofunc)instancemethod_getattro,	/* tp_getattro */
! 	PyObject_GenericSetAttr,		/* tp_setattro */
  	0,					/* tp_as_buffer */
  	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
***************
*** 2310,2315 ****
  	0,					/* tp_iternext */
  	0,					/* tp_methods */
! 	0,					/* tp_members */
! 	0,					/* tp_getset */
  	0,					/* tp_base */
  	0,					/* tp_dict */
--- 2342,2347 ----
  	0,					/* tp_iternext */
  	0,					/* tp_methods */
! 	instancemethod_memberlist,		/* tp_members */
! 	instancemethod_getsetlist,		/* tp_getset */
  	0,					/* tp_base */
  	0,					/* tp_dict */