diff -r bff88c866886 Lib/collections/__init__.py --- a/Lib/collections/__init__.py Thu Apr 09 10:27:25 2015 +0200 +++ b/Lib/collections/__init__.py Sat Apr 11 03:05:27 2015 -0400 @@ -270,8 +270,7 @@ _class_template = """\ from builtins import property as _property, tuple as _tuple -from operator import itemgetter as _itemgetter -from collections import OrderedDict +from collections import OrderedDict, _namedtuple_indexer class {typename}(tuple): '{typename}({arg_list})' @@ -326,9 +325,26 @@ _repr_template = '{name}=%r' _field_template = '''\ - {name} = _property(_itemgetter({index:d}), doc='Alias for field number {index:d}') + {name} = _namedtuple_indexer({index:d}) ''' +try: + from _collections import _namedtuple_indexer +except ImportError: + + class _namedtuple_indexer(object): + "A specialized 'itemgetter' for namedtuples" + + def __init__(self, index): + self._index = index + + def __get__(self, instance, owner): + if instance is None: + return self + else: + return instance[self._index] + + def namedtuple(typename, field_names, verbose=False, rename=False): """Returns a new subclass of tuple with named fields. diff -r bff88c866886 Modules/_collectionsmodule.c --- a/Modules/_collectionsmodule.c Thu Apr 09 10:27:25 2015 +0200 +++ b/Modules/_collectionsmodule.c Sat Apr 11 03:05:27 2015 -0400 @@ -2218,6 +2218,113 @@ Py_RETURN_NONE; } +/* namedtuple ***************************************************************/ + +/* The type of the descriptors that access the named fields of the + `namedtuple` types. */ +typedef struct{ + PyObject id_ob; + Py_ssize_t id_idx; /* The index that this will access. */ +}namedtuple_indexer; + +static PyTypeObject namedtuple_indexer_type; + +/* Index a tuple at `self`'s index like a specialized `itemgetter`. */ +static PyObject * +namedtuple_indexer_get(PyObject *self, PyObject *instance, PyObject *owner) +{ + PyObject *ret; + + if (!instance) { + /* If this is called on the owner, then just return this object. */ + ret = self; + } + else { + /* Assert that this is a tuple subclass. */ + if (!PyTuple_Check(instance)) { + PyErr_Format(PyExc_TypeError, + "%s objects can only be used on tuple types", + ((PyTypeObject*) self->ob_type)->tp_name); + return NULL; + } + + if (!(ret = PyTuple_GetItem(instance, + ((namedtuple_indexer*) self)->id_idx))) { + return NULL; + } + } + + Py_INCREF(ret); + return ret; +} + +static PyObject * +namedtuple_indexer_new(PyObject *cls, PyObject *args, PyObject *kwargs) { + static const char *keywords[] = {"index", NULL}; + Py_ssize_t idx; + namedtuple_indexer *self; + + if (!PyArg_ParseTupleAndKeywords(args, + kwargs, + "n:NamedTupleIndexer", + (char**) keywords, + &idx)) { + return NULL; + } + + if (!(self = PyObject_GC_New(namedtuple_indexer, + &namedtuple_indexer_type))) { + return NULL; + } + + self->id_idx = idx; + return (PyObject*) self; +} + +PyDoc_STRVAR(namedtuple_indexer_doc, "A specialized 'itemgetter' for namedtuples"); + +/* A specialized `itemgetter` for namedtuples. */ +static PyTypeObject namedtuple_indexer_type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "_collections._namedtuple_indexer", /* tp_name */ + sizeof(namedtuple_indexer), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) PyObject_GC_Del, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 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, /* tp_flags */ + namedtuple_indexer_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + namedtuple_indexer_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + (newfunc) namedtuple_indexer_new, /* tp_new */ +}; + /* module level code ********************************************************/ PyDoc_STRVAR(module_doc, @@ -2273,5 +2380,11 @@ Py_INCREF(&dequereviter_type); PyModule_AddObject(m, "_deque_reverse_iterator", (PyObject *)&dequereviter_type); + if (PyType_Ready(&namedtuple_indexer_type) < 0) { + return NULL; + } + Py_INCREF(&dequeiter_type); + PyModule_AddObject(m, "_namedtuple_indexer", (PyObject *)&namedtuple_indexer_type); + return m; }