forked from python/cpython
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- New builtin function enumerate(x), from PEP 279. Example:
enumerate("abc") is an iterator returning (0,"a"), (1,"b"), (2,"c"). The argument can be an arbitrary iterable object.
- Loading branch information
1 parent
17afa13
commit 7dab242
Showing
7 changed files
with
281 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#ifndef Py_ENUMOBJECT_H | ||
#define Py_ENUMOBJECT_H | ||
|
||
/* Enumerate Object */ | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
extern DL_IMPORT(PyTypeObject) PyEnum_Type; | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* !Py_ENUMOBJECT_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
from __future__ import generators | ||
import unittest | ||
|
||
import test_support | ||
|
||
seq, res = 'abc', [(0,'a'), (1,'b'), (2,'c')] | ||
|
||
class G: | ||
'Sequence using __getitem__' | ||
def __init__(self, seqn): | ||
self.seqn = seqn | ||
def __getitem__(self, i): | ||
return self.seqn[i] | ||
|
||
class I: | ||
'Sequence using iterator protocol' | ||
def __init__(self, seqn): | ||
self.seqn = seqn | ||
self.i = 0 | ||
def __iter__(self): | ||
return self | ||
def next(self): | ||
if self.i >= len(self.seqn): raise StopIteration | ||
v = self.seqn[self.i] | ||
self.i += 1 | ||
return v | ||
|
||
class Ig: | ||
'Sequence using iterator protocol defined with a generator' | ||
def __init__(self, seqn): | ||
self.seqn = seqn | ||
self.i = 0 | ||
def __iter__(self): | ||
for val in self.seqn: | ||
yield val | ||
|
||
class X: | ||
'Missing __getitem__ and __iter__' | ||
def __init__(self, seqn): | ||
self.seqn = seqn | ||
self.i = 0 | ||
def next(self): | ||
if self.i >= len(self.seqn): raise StopIteration | ||
v = self.seqn[self.i] | ||
self.i += 1 | ||
return v | ||
|
||
class E: | ||
'Test propagation of exceptions' | ||
def __init__(self, seqn): | ||
self.seqn = seqn | ||
self.i = 0 | ||
def __iter__(self): | ||
return self | ||
def next(self): | ||
3/0 | ||
|
||
class N: | ||
'Iterator missing next()' | ||
def __init__(self, seqn): | ||
self.seqn = seqn | ||
self.i = 0 | ||
def __iter__(self): | ||
return self | ||
|
||
class EnumerateTestCase(unittest.TestCase): | ||
|
||
enum = enumerate | ||
|
||
def test_basicfunction(self): | ||
self.assertEqual(type(self.enum(seq)), self.enum) | ||
e = self.enum(seq) | ||
self.assertEqual(iter(e), e) | ||
self.assertEqual(list(self.enum(seq)), res) | ||
self.enum.__doc__ | ||
|
||
def test_getitemseqn(self): | ||
self.assertEqual(list(self.enum(G(seq))), res) | ||
e = self.enum(G('')) | ||
self.assertRaises(StopIteration, e.next) | ||
|
||
def test_iteratorseqn(self): | ||
self.assertEqual(list(self.enum(I(seq))), res) | ||
e = self.enum(I('')) | ||
self.assertRaises(StopIteration, e.next) | ||
|
||
def test_iteratorgenerator(self): | ||
self.assertEqual(list(self.enum(Ig(seq))), res) | ||
e = self.enum(Ig('')) | ||
self.assertRaises(StopIteration, e.next) | ||
|
||
def test_noniterable(self): | ||
self.assertRaises(TypeError, self.enum, X(seq)) | ||
|
||
def test_illformediterable(self): | ||
self.assertRaises(TypeError, list, self.enum(N(seq))) | ||
|
||
def test_exception_propagation(self): | ||
self.assertRaises(ZeroDivisionError, list, self.enum(E(seq))) | ||
|
||
class MyEnum(enumerate): | ||
pass | ||
|
||
class SubclassTestCase(EnumerateTestCase): | ||
|
||
enum = MyEnum | ||
|
||
def suite(): | ||
suite = unittest.TestSuite() | ||
suite.addTest(unittest.makeSuite(EnumerateTestCase)) | ||
suite.addTest(unittest.makeSuite(SubclassTestCase)) | ||
return suite | ||
|
||
def test_main(): | ||
test_support.run_suite(suite()) | ||
|
||
if __name__ == "__main__": | ||
test_main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* enumerate object */ | ||
|
||
#include "Python.h" | ||
|
||
typedef struct { | ||
PyObject_HEAD | ||
long en_index; /* current index of enumeration */ | ||
PyObject* en_sit; /* secondary iterator of enumeration */ | ||
} enumobject; | ||
|
||
PyTypeObject PyEnum_Type; | ||
|
||
static PyObject * | ||
enum_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | ||
{ | ||
enumobject *en; | ||
PyObject *seq = NULL; | ||
static char *kwlist[] = {"sequence", 0}; | ||
|
||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:enumerate", kwlist, | ||
&seq)) | ||
return NULL; | ||
|
||
en = (enumobject *)type->tp_alloc(type, 0); | ||
if (en == NULL) | ||
return NULL; | ||
en->en_index = 0; | ||
en->en_sit = PyObject_GetIter(seq); | ||
if (en->en_sit == NULL) { | ||
Py_DECREF(en); | ||
return NULL; | ||
} | ||
return (PyObject *)en; | ||
} | ||
|
||
static void | ||
enum_dealloc(enumobject *en) | ||
{ | ||
PyObject_GC_UnTrack(en); | ||
Py_XDECREF(en->en_sit); | ||
en->ob_type->tp_free(en); | ||
} | ||
|
||
static int | ||
enum_traverse(enumobject *en, visitproc visit, void *arg) | ||
{ | ||
if (en->en_sit) | ||
return visit(en->en_sit, arg); | ||
return 0; | ||
} | ||
|
||
static PyObject * | ||
enum_next(enumobject *en) | ||
{ | ||
PyObject *result; | ||
PyObject *next_index; | ||
|
||
PyObject *next_item = PyIter_Next(en->en_sit); | ||
if (next_item == NULL) | ||
return NULL; | ||
|
||
result = PyTuple_New(2); | ||
if (result == NULL) { | ||
Py_DECREF(next_item); | ||
return NULL; | ||
} | ||
|
||
next_index = PyInt_FromLong(en->en_index++); | ||
if (next_index == NULL) { | ||
Py_DECREF(next_item); | ||
Py_DECREF(result); | ||
return NULL; | ||
} | ||
|
||
PyTuple_SET_ITEM(result, 0, next_index); | ||
PyTuple_SET_ITEM(result, 1, next_item); | ||
return result; | ||
} | ||
|
||
static PyObject * | ||
enum_getiter(PyObject *en) | ||
{ | ||
Py_INCREF(en); | ||
return en; | ||
} | ||
|
||
static PyMethodDef enum_methods[] = { | ||
{"next", (PyCFunction)enum_next, METH_NOARGS, | ||
"return the next (index, value) pair, or raise StopIteration"}, | ||
{NULL, NULL} /* sentinel */ | ||
}; | ||
|
||
static char enum_doc[] = | ||
"enumerate(iterable) -> create an enumerating-iterator"; | ||
|
||
PyTypeObject PyEnum_Type = { | ||
PyObject_HEAD_INIT(&PyType_Type) | ||
0, /* ob_size */ | ||
"enumerate", /* tp_name */ | ||
sizeof(enumobject), /* tp_basicsize */ | ||
0, /* tp_itemsize */ | ||
/* methods */ | ||
(destructor)enum_dealloc, /* tp_dealloc */ | ||
0, /* tp_print */ | ||
0, /* 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 */ | ||
PyObject_GenericGetAttr, /* tp_getattro */ | ||
0, /* tp_setattro */ | ||
0, /* tp_as_buffer */ | ||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | | ||
Py_TPFLAGS_BASETYPE, /* tp_flags */ | ||
enum_doc, /* tp_doc */ | ||
(traverseproc)enum_traverse, /* tp_traverse */ | ||
0, /* tp_clear */ | ||
0, /* tp_richcompare */ | ||
0, /* tp_weaklistoffset */ | ||
(getiterfunc)enum_getiter, /* tp_iter */ | ||
(iternextfunc)enum_next, /* tp_iternext */ | ||
enum_methods, /* tp_methods */ | ||
0, /* tp_members */ | ||
0, /* tp_getset */ | ||
0, /* tp_base */ | ||
0, /* tp_dict */ | ||
0, /* tp_descr_get */ | ||
0, /* tp_descr_set */ | ||
0, /* tp_dictoffset */ | ||
0, /* tp_init */ | ||
PyType_GenericAlloc, /* tp_alloc */ | ||
enum_new, /* tp_new */ | ||
PyObject_GC_Del, /* tp_free */ | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters