[Python-checkins] CVS: python/dist/src/Objects abstract.c,2.58,2.59 classobject.c,2.125,2.126 dictobject.c,2.78,2.79 stringobject.c,2.102,2.103

Guido van Rossum gvanrossum@users.sourceforge.net
Fri, 20 Apr 2001 12:13:04 -0700


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

Modified Files:
	abstract.c classobject.c dictobject.c stringobject.c 
Log Message:
Iterators phase 1.  This comprises:

new slot tp_iter in type object, plus new flag Py_TPFLAGS_HAVE_ITER
new C API PyObject_GetIter(), calls tp_iter
new builtin iter(), with two forms: iter(obj), and iter(function, sentinel)
new internal object types iterobject and calliterobject
new exception StopIteration
new opcodes for "for" loops, GET_ITER and FOR_ITER (also supported by dis.py)
new magic number for .pyc files
new special method for instances: __iter__() returns an iterator
iteration over dictionaries: "for x in dict" iterates over the keys
iteration over files: "for x in file" iterates over lines

TODO:

documentation
test suite
decide whether to use a different way to spell iter(function, sentinal)
decide whether "for key in dict" is a good idea
use iterators in map/filter/reduce, min/max, and elsewhere (in/not in?)
speed tuning (make next() a slot tp_next???)



Index: abstract.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v
retrieving revision 2.58
retrieving revision 2.59
diff -C2 -r2.58 -r2.59
*** abstract.c	2001/03/21 18:40:58	2.58
--- abstract.c	2001/04/20 19:13:02	2.59
***************
*** 1739,1740 ****
--- 1739,1757 ----
  	return retval;
  }
+ 
+ PyObject *
+ PyObject_GetIter(PyObject *o)
+ {
+ 	PyTypeObject *t = o->ob_type;
+ 	getiterfunc f = NULL;
+ 	if (PyType_HasFeature(t, Py_TPFLAGS_HAVE_ITER))
+ 		f = t->tp_iter;
+ 	if (f == NULL) {
+ 		if (PySequence_Check(o))
+ 			return PyIter_New(o);
+ 		PyErr_SetString(PyExc_TypeError, "iter() of non-sequence");
+ 		return NULL;
+ 	}
+ 	else
+ 		return (*f)(o);
+ }

Index: classobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/classobject.c,v
retrieving revision 2.125
retrieving revision 2.126
diff -C2 -r2.125 -r2.126
*** classobject.c	2001/03/23 04:19:27	2.125
--- classobject.c	2001/04/20 19:13:02	2.126
***************
*** 849,853 ****
  }
  
! static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr;
  
  static int
--- 849,853 ----
  }
  
! static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr, *iterstr;
  
  static int
***************
*** 1713,1716 ****
--- 1713,1742 ----
  
  
+ /* Get the iterator */
+ static PyObject *
+ instance_getiter(PyInstanceObject *self)
+ {
+ 	PyObject *func;
+ 
+ 	if (iterstr == NULL)
+ 		iterstr = PyString_InternFromString("__iter__");
+ 	if (getitemstr == NULL)
+ 		getitemstr = PyString_InternFromString("__getitem__");
+ 
+ 	if ((func = instance_getattr(self, iterstr)) != NULL) {
+ 		PyObject *res = PyEval_CallObject(func, (PyObject *)NULL);
+ 		Py_DECREF(func);
+ 		return res;
+ 	}
+ 	PyErr_Clear();
+ 	if ((func = instance_getattr(self, getitemstr)) == NULL) {
+ 		PyErr_SetString(PyExc_TypeError, "iter() of non-sequence");
+ 		return NULL;
+ 	}
+ 	Py_DECREF(func);
+ 	return PyIter_New((PyObject *)self);
+ }
+ 
+ 
  static PyNumberMethods instance_as_number = {
  	(binaryfunc)instance_add,		/* nb_add */
***************
*** 1776,1780 ****
  	0,					/* tp_clear */
  	instance_richcompare,			/* tp_richcompare */
!  	offsetof(PyInstanceObject, in_weakreflist) /* tp_weaklistoffset */
  };
  
--- 1802,1807 ----
  	0,					/* tp_clear */
  	instance_richcompare,			/* tp_richcompare */
!  	offsetof(PyInstanceObject, in_weakreflist), /* tp_weaklistoffset */
! 	(getiterfunc)instance_getiter,		/* tp_iter */
  };
  

Index: dictobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/dictobject.c,v
retrieving revision 2.78
retrieving revision 2.79
diff -C2 -r2.78 -r2.79
*** dictobject.c	2001/04/20 16:52:06	2.78
--- dictobject.c	2001/04/20 19:13:02	2.79
***************
*** 1325,1328 ****
--- 1325,1330 ----
  };
  
+ staticforward PyObject *dictiter_new(dictobject *);
+ 
  PyTypeObject PyDict_Type = {
  	PyObject_HEAD_INIT(&PyType_Type)
***************
*** 1351,1354 ****
--- 1353,1358 ----
  	(inquiry)dict_tp_clear,			/* tp_clear */
  	0,					/* tp_richcompare */
+ 	0,					/* tp_weaklistoffset */
+ 	(getiterfunc)dictiter_new,		/* tp_iter */
  };
  
***************
*** 1393,1394 ****
--- 1397,1497 ----
  	return err;
  }
+ 
+ /* Dictionary iterator type */
+ 
+ extern PyTypeObject PyDictIter_Type; /* Forward */
+ 
+ typedef struct {
+ 	PyObject_HEAD
+ 	dictobject *di_dict;
+ 	int di_size;
+ 	int di_pos;
+ } dictiterobject;
+ 
+ static PyObject *
+ dictiter_new(dictobject *dict)
+ {
+ 	dictiterobject *di;
+ 	di = PyObject_NEW(dictiterobject, &PyDictIter_Type);
+ 	if (di == NULL)
+ 		return NULL;
+ 	Py_INCREF(dict);
+ 	di->di_dict = dict;
+ 	di->di_size = dict->ma_size;
+ 	di->di_pos = 0;
+ 	return (PyObject *)di;
+ }
+ 
+ static void
+ dictiter_dealloc(dictiterobject *di)
+ {
+ 	Py_DECREF(di->di_dict);
+ 	PyObject_DEL(di);
+ }
+ 
+ static PyObject *
+ dictiter_next(dictiterobject *di, PyObject *args)
+ {
+ 	PyObject *key;
+ 	if (di->di_size != di->di_dict->ma_size) {
+ 		PyErr_SetString(PyExc_RuntimeError,
+ 				"dictionary changed size during iteration");
+ 		return NULL;
+ 	}
+ 	if (PyDict_Next((PyObject *)(di->di_dict), &di->di_pos, &key, NULL)) {
+ 		Py_INCREF(key);
+ 		return key;
+ 	}
+ 	PyErr_SetObject(PyExc_StopIteration, Py_None);
+ 	return NULL;
+ }
+ 
+ static PyObject *
+ dictiter_getiter(PyObject *it)
+ {
+ 	Py_INCREF(it);
+ 	return it;
+ }
+ 
+ static PyMethodDef dictiter_methods[] = {
+ 	{"next",	(PyCFunction)dictiter_next,	METH_VARARGS,
+ 	 "it.next() -- get the next value, or raise StopIteration"},
+ 	{NULL,		NULL}		/* sentinel */
+ };
+ 
+ static PyObject *
+ dictiter_getattr(dictiterobject *it, char *name)
+ {
+ 	return Py_FindMethod(dictiter_methods, (PyObject *)it, name);
+ }
+ 
+ PyTypeObject PyDictIter_Type = {
+ 	PyObject_HEAD_INIT(&PyType_Type)
+ 	0,					/* ob_size */
+ 	"dictionary-iterator",			/* tp_name */
+ 	sizeof(dictiterobject),			/* tp_basicsize */
+ 	0,					/* tp_itemsize */
+ 	/* methods */
+ 	(destructor)dictiter_dealloc, 		/* tp_dealloc */
+ 	0,					/* tp_print */
+ 	(getattrfunc)dictiter_getattr,		/* tp_getattr */
+ 	0,					/* tp_setattr */
+ 	0,					/* tp_compare */
+ 	0,					/* tp_repr */
+ 	0,					/* tp_as_number */
+ 	0,					/* tp_as_sequence */
+ 	0,					/* tp_as_mapping */
+ 	0,					/* tp_hash */
+ 	0,					/* tp_call */
+ 	0,					/* tp_str */
+ 	0,					/* tp_getattro */
+ 	0,					/* tp_setattro */
+ 	0,					/* tp_as_buffer */
+ 	Py_TPFLAGS_DEFAULT,			/* tp_flags */
+  	0,					/* tp_doc */
+  	0,					/* tp_traverse */
+  	0,					/* tp_clear */
+ 	0,					/* tp_richcompare */
+ 	0,					/* tp_weaklistoffset */
+ 	(getiterfunc)dictiter_getiter,		/* tp_iter */
+ };

Index: stringobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/stringobject.c,v
retrieving revision 2.102
retrieving revision 2.103
diff -C2 -r2.102 -r2.103
*** stringobject.c	2001/04/12 18:38:48	2.102
--- stringobject.c	2001/04/20 19:13:02	2.103
***************
*** 3233,3236 ****
--- 3233,3238 ----
  {
  	if (interned) {
+ 		fprintf(stderr, "releasing interned strings\n");
+ 		PyDict_Clear(interned);
  		Py_DECREF(interned);
  		interned = NULL;