[Python-3000-checkins] r59469 - in python/branches/py3k: Doc/c-api/concrete.rst Include/classobject.h Misc/NEWS Objects/classobject.c

christian.heimes python-3000-checkins at python.org
Tue Dec 11 20:56:41 CET 2007


Author: christian.heimes
Date: Tue Dec 11 20:56:40 2007
New Revision: 59469

Modified:
   python/branches/py3k/Doc/c-api/concrete.rst
   python/branches/py3k/Include/classobject.h
   python/branches/py3k/Misc/NEWS
   python/branches/py3k/Objects/classobject.c
Log:
Issue #1587: Added instancemethod wrapper for PyCFunctions. The Python C API
has gained a new type *PyInstanceMethod_Type* and the functions
*PyInstanceMethod_Check(o)*, *PyInstanceMethod_New(func)* and
*PyInstanceMethod_Function(im)*.

Modified: python/branches/py3k/Doc/c-api/concrete.rst
==============================================================================
--- python/branches/py3k/Doc/c-api/concrete.rst	(original)
+++ python/branches/py3k/Doc/c-api/concrete.rst	Tue Dec 11 20:56:40 2007
@@ -2522,6 +2522,47 @@
    Raises :exc:`SystemError` and returns ``-1`` on failure.
 
 
+.. _instancemethod-objects:
+
+Instance Method Objects
+-----------------------
+
+.. index:: object: instancemethod
+
+An instance method is a wrapper for a :cdata:`PyCFunction` and the new way
+to bind a :cdata:`PyCFunction` to a class object. It replaces the former call
+:cfunc:`PyMethod_New(func, NULL, class)`.
+
+
+.. cvar:: PyTypeObject PyInstanceMethod_Type
+
+   This instance of :ctype:`PyTypeObject` represents the Python instance
+   method type. It is not exposed to Python programs.
+
+
+.. cfunction:: int PyInstanceMethod_Check(PyObject *o)
+
+   Return true if *o* is an instance method object (has type
+   :cdata:`PyInstanceMethod_Type`).  The parameter must not be *NULL*.
+
+
+.. cfunction:: PyObject* PyInstanceMethod_New(PyObject *func)
+
+   Return a new instance method object, with *func* being any callable object
+   *func* is is the function that will be called when the instance method is
+   called.
+
+
+.. cfunction:: PyObject* PyInstanceMethod_Function(PyObject *im)
+
+   Return the function object associated with the instance method *im*.
+
+
+.. cfunction:: PyObject* PyInstanceMethod_GET_FUNCTION(PyObject *im)
+
+   Macro version of :cfunc:`PyInstanceMethod_Function` which avoids error checking.
+
+
 .. _method-objects:
 
 Method Objects

Modified: python/branches/py3k/Include/classobject.h
==============================================================================
--- python/branches/py3k/Include/classobject.h	(original)
+++ python/branches/py3k/Include/classobject.h	Tue Dec 11 20:56:40 2007
@@ -31,6 +31,24 @@
 #define PyMethod_GET_SELF(meth) \
 	(((PyMethodObject *)meth) -> im_self)
 
+
+typedef struct {
+	PyObject_HEAD
+	PyObject *func;
+} PyInstanceMethodObject;
+
+PyAPI_DATA(PyTypeObject) PyInstanceMethod_Type;
+
+#define PyInstanceMethod_Check(op) ((op)->ob_type == &PyInstanceMethod_Type)
+
+PyAPI_FUNC(PyObject *) PyInstanceMethod_New(PyObject *);
+PyAPI_FUNC(PyObject *) PyInstanceMethod_Function(PyObject *);
+
+/* Macros for direct access to these values. Type checks are *not*
+   done, so use with care. */
+#define PyInstanceMethod_GET_FUNCTION(meth) \
+        (((PyInstanceMethodObject *)meth) -> func)
+
 #ifdef __cplusplus
 }
 #endif

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Tue Dec 11 20:56:40 2007
@@ -12,6 +12,11 @@
 Core and Builtins
 -----------------
 
+- Issue #1587: Added instancemethod wrapper for PyCFunctions. The Python C API
+  has gained a new type *PyInstanceMethod_Type* and the functions
+  *PyInstanceMethod_Check(o)*, *PyInstanceMethod_New(func)* and
+  *PyInstanceMethod_Function(im)*.
+
 - Constants gc.DEBUG_OBJECT and gc.DEBUG_INSTANCE have been removed from the
   gc module; gc.DEBUG_COLLECTABLE or gc.DEBUG_UNCOLLECTABLE are now enough to
   print the corresponding list of objects considered by the garbage collector.

Modified: python/branches/py3k/Objects/classobject.c
==============================================================================
--- python/branches/py3k/Objects/classobject.c	(original)
+++ python/branches/py3k/Objects/classobject.c	Tue Dec 11 20:56:40 2007
@@ -5,7 +5,6 @@
 
 #define TP_DESCR_GET(t) ((t)->tp_descr_get)
 
-
 PyObject *
 PyMethod_Function(PyObject *im)
 {
@@ -68,12 +67,12 @@
 
 /* im_func and im_self are stored in the PyMethod object */
 
-#define OFF(x) offsetof(PyMethodObject, x)
+#define MO_OFF(x) offsetof(PyMethodObject, x)
 
 static PyMemberDef method_memberlist[] = {
-	{"__func__",	T_OBJECT,	OFF(im_func),	READONLY|RESTRICTED,
+	{"__func__", T_OBJECT, MO_OFF(im_func), READONLY|RESTRICTED,
 	 "the function (or other callable) implementing a method"},
-	{"__self__",	T_OBJECT,	OFF(im_self),	READONLY|RESTRICTED,
+	{"__self__", T_OBJECT, MO_OFF(im_self), READONLY|RESTRICTED,
 	 "the instance to which a method is bound"},
 	{NULL}	/* Sentinel */
 };
@@ -131,7 +130,7 @@
 PyDoc_STRVAR(method_doc,
 "method(function, instance)\n\
 \n\
-Create an instance method object.");
+Create a bound instance method object.");
 
 static PyObject *
 method_new(PyTypeObject* type, PyObject* args, PyObject *kw)
@@ -139,7 +138,7 @@
 	PyObject *func;
 	PyObject *self;
 
-	if (!_PyArg_NoKeywords("instancemethod", kw))
+	if (!_PyArg_NoKeywords("method", kw))
 		return NULL;
 	if (!PyArg_UnpackTuple(args, "method", 2, 2,
 			      &func, &self))
@@ -351,7 +350,7 @@
 	(traverseproc)method_traverse,		/* tp_traverse */
 	0,					/* tp_clear */
 	method_richcompare,			/* tp_richcompare */
- 	offsetof(PyMethodObject, im_weakreflist), /* tp_weaklistoffset */
+	offsetof(PyMethodObject, im_weakreflist), /* tp_weaklistoffset */
 	0,					/* tp_iter */
 	0,					/* tp_iternext */
 	0,					/* tp_methods */
@@ -378,3 +377,245 @@
 		PyObject_GC_Del(im);
 	}
 }
+
+/* ------------------------------------------------------------------------
+ * instance method
+ */
+
+PyObject *
+PyInstanceMethod_New(PyObject *func) {
+	PyInstanceMethodObject *method;
+	method = PyObject_GC_New(PyInstanceMethodObject,
+				 &PyInstanceMethod_Type);
+	if (method == NULL) return NULL;
+	Py_INCREF(func);
+	method->func = func;
+	_PyObject_GC_TRACK(method);
+	return (PyObject *)method;
+}
+
+PyObject *
+PyInstanceMethod_Function(PyObject *im)
+{
+	if (!PyInstanceMethod_Check(im)) {
+		PyErr_BadInternalCall();
+		return NULL;
+	}
+	return PyInstanceMethod_GET_FUNCTION(im);
+}
+
+#define IMO_OFF(x) offsetof(PyInstanceMethodObject, x)
+
+static PyMemberDef instancemethod_memberlist[] = {
+	{"__func__", T_OBJECT, IMO_OFF(func), READONLY|RESTRICTED,
+	 "the function (or other callable) implementing a method"},
+	{NULL}	/* Sentinel */
+};
+
+static PyObject *
+instancemethod_get_doc(PyObject *self, void *context)
+{
+	static PyObject *docstr;
+	if (docstr == NULL) {
+		docstr = PyUnicode_InternFromString("__doc__");
+		if (docstr == NULL)
+			return NULL;
+	}
+	return PyObject_GetAttr(PyInstanceMethod_GET_FUNCTION(self), docstr);
+}
+
+static PyGetSetDef instancemethod_getset[] = {
+	{"__doc__", (getter)instancemethod_get_doc, NULL, NULL},
+	{0}
+};
+
+static PyObject *
+instancemethod_getattro(PyObject *self, PyObject *name)
+{
+	PyTypeObject *tp = self->ob_type;
+	PyObject *descr = NULL;
+
+	if (tp->tp_dict == NULL) {
+		if (PyType_Ready(tp) < 0)
+			return NULL;
+	}
+	descr = _PyType_Lookup(tp, name);
+
+	if (descr != NULL) {
+		descrgetfunc f = TP_DESCR_GET(descr->ob_type);
+		if (f != NULL)
+			return f(descr, self, (PyObject *)self->ob_type);
+		else {
+			Py_INCREF(descr);
+			return descr;
+		}
+	}
+
+	return PyObject_GetAttr(PyInstanceMethod_GET_FUNCTION(self), name);
+}
+
+static void
+instancemethod_dealloc(PyObject *self) {
+	_PyObject_GC_UNTRACK(self);
+	Py_DECREF(PyInstanceMethod_GET_FUNCTION(self));
+	PyObject_GC_Del(self);
+}
+
+static int
+instancemethod_traverse(PyObject *self, visitproc visit, void *arg) {
+	Py_VISIT(PyInstanceMethod_GET_FUNCTION(self));
+	return 0;
+}
+
+static PyObject *
+instancemethod_call(PyObject *self, PyObject *arg, PyObject *kw)
+{
+	return PyObject_Call(PyMethod_GET_FUNCTION(self), arg, kw);
+}
+
+static PyObject *
+instancemethod_descr_get(PyObject *descr, PyObject *obj, PyObject *type) {
+	register PyObject *func = PyInstanceMethod_GET_FUNCTION(descr);
+	if (obj == NULL)
+		return func;
+	else
+		return PyMethod_New(func, obj);
+}
+
+static PyObject *
+instancemethod_richcompare(PyObject *self, PyObject *other, int op)
+{
+	PyInstanceMethodObject *a, *b;
+	PyObject *res;
+	int eq;
+
+	if ((op != Py_EQ && op != Py_NE) ||
+	    !PyInstanceMethod_Check(self) ||
+	    !PyInstanceMethod_Check(other))
+	{
+		Py_INCREF(Py_NotImplemented);
+		return Py_NotImplemented;
+	}
+	a = (PyInstanceMethodObject *)self;
+	b = (PyInstanceMethodObject *)other;
+	eq = PyObject_RichCompareBool(a->func, b->func, Py_EQ);
+	if (eq < 0)
+		return NULL;
+	if (op == Py_EQ)
+		res = eq ? Py_True : Py_False;
+	else
+		res = eq ? Py_False : Py_True;
+	Py_INCREF(res);
+	return res;
+}
+
+static PyObject *
+instancemethod_repr(PyObject *self)
+{
+	PyObject *func = PyInstanceMethod_Function(self);
+	PyObject *funcname = NULL , *result = NULL;
+	char *defname = "?";
+
+	if (func == NULL) {
+		PyErr_BadInternalCall();
+		return NULL;
+	}
+
+	funcname = PyObject_GetAttrString(func, "__name__");
+	if (funcname == NULL) {
+		if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+			return NULL;
+		PyErr_Clear();
+	}
+	else if (!PyUnicode_Check(funcname)) {
+		Py_DECREF(funcname);
+		funcname = NULL;
+	}
+
+	result = PyUnicode_FromFormat("<instancemethod %V at %p>",
+	                              funcname, defname, self);
+
+	Py_XDECREF(funcname);
+	return result;
+}
+
+/*
+static long
+instancemethod_hash(PyObject *self)
+{
+	long x, y;
+	x = (long)self;
+	y = PyObject_Hash(PyInstanceMethod_GET_FUNCTION(self));
+	if (y == -1)
+		return -1;
+	x = x ^ y;
+	if (x == -1)
+		x = -2;
+	return x;
+}
+*/
+
+PyDoc_STRVAR(instancemethod_doc,
+"instancemethod(function)\n\
+\n\
+Bind a function to a class.");
+
+static PyObject *
+instancemethod_new(PyTypeObject* type, PyObject* args, PyObject *kw)
+{
+	PyObject *func;
+
+	if (!_PyArg_NoKeywords("instancemethod", kw))
+		return NULL;
+	if (!PyArg_UnpackTuple(args, "instancemethod", 1, 1, &func))
+		return NULL;
+	if (!PyCallable_Check(func)) {
+		PyErr_SetString(PyExc_TypeError,
+				"first argument must be callable");
+		return NULL;
+	}
+
+	return PyInstanceMethod_New(func);
+}
+
+PyTypeObject PyInstanceMethod_Type = {
+	PyVarObject_HEAD_INIT(&PyType_Type, 0)
+	"instancemethod",			/* tp_name */
+	sizeof(PyInstanceMethodObject),		/* tp_basicsize */
+	0,					/* tp_itemsize */
+	instancemethod_dealloc,			/* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	(reprfunc)instancemethod_repr,		/* tp_repr */
+	0,					/* tp_as_number */
+	0,					/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0, /*(hashfunc)instancemethod_hash,	tp_hash  */
+	instancemethod_call,			/* tp_call */
+	0,					/* tp_str */
+	instancemethod_getattro,		/* tp_getattro */
+	PyObject_GenericSetAttr,		/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT
+		| Py_TPFLAGS_HAVE_GC,		/* tp_flags */
+	instancemethod_doc,			/* tp_doc */
+	instancemethod_traverse,		/* tp_traverse */
+	0,					/* tp_clear */
+	instancemethod_richcompare,		/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	0,					/* tp_iter */
+	0,					/* tp_iternext */
+	0,					/* tp_methods */
+	instancemethod_memberlist,		/* tp_members */
+	instancemethod_getset,			/* tp_getset */
+	0,					/* tp_base */
+	0,					/* tp_dict */
+	instancemethod_descr_get,		/* tp_descr_get */
+	0,					/* tp_descr_set */
+	0,					/* tp_dictoffset */
+	0,					/* tp_init */
+	0,					/* tp_alloc */
+	instancemethod_new,			/* tp_new */
+};


More information about the Python-3000-checkins mailing list