New submission from Christian Heimes:

The patch implements the instancemethod wrapper as discussed on the py3k
mailing list. The patch is roughly based on Marcin Kowalczyk patch but
it contains more fancy slots like repr, call etc. The rest is mostly
based on PyMethod_Type.

----------
components: Interpreter Core
files: py3k_instancemethod.patch
keywords: patch, py3k
messages: 58425
nosy: tiran
priority: normal
severity: normal
status: open
title: instancemethod wrapper for PyCFunctions
type: rfe
versions: Python 3.0
Added file: http://bugs.python.org/file8923/py3k_instancemethod.patch

__________________________________
Tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue1587>
__________________________________
Index: Python/bltinmodule.c
===================================================================
--- Python/bltinmodule.c	(Revision 59464)
+++ Python/bltinmodule.c	(Arbeitskopie)
@@ -1903,6 +1903,7 @@
 	SETBUILTIN("frozenset",		&PyFrozenSet_Type);
 	SETBUILTIN("property",		&PyProperty_Type);
 	SETBUILTIN("int",		&PyLong_Type);
+	SETBUILTIN("instancemethod",	&PyInstanceMethod_Type);
 	SETBUILTIN("list",		&PyList_Type);
 	SETBUILTIN("object",		&PyBaseObject_Type);
 	SETBUILTIN("range",		&PyRange_Type);
Index: Include/classobject.h
===================================================================
--- Include/classobject.h	(Revision 59464)
+++ Include/classobject.h	(Arbeitskopie)
@@ -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
Index: Objects/classobject.c
===================================================================
--- Objects/classobject.c	(Revision 59464)
+++ Objects/classobject.c	(Arbeitskopie)
@@ -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,243 @@
 		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 */
+	(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 */
+};
_______________________________________________
Python-bugs-list mailing list 
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to