diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index ba3ce31d1c6..0b856fe225c 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -10,7 +10,7 @@ This module implements high-performance container datatypes. Currently, there are two datatypes, :class:`deque` and :class:`defaultdict`, and -one datatype factory function, :func:`named_tuple`. Python already +one datatype factory function, :func:`namedtuple`. Python already includes built-in containers, :class:`dict`, :class:`list`, :class:`set`, and :class:`tuple`. In addition, the optional :mod:`bsddb` module has a :meth:`bsddb.btopen` method that can be used to create in-memory @@ -383,14 +383,14 @@ Setting the :attr:`default_factory` to :class:`set` makes the .. _named-tuple-factory: -:func:`named_tuple` Factory Function for Tuples with Named Fields +:func:`namedtuple` Factory Function for Tuples with Named Fields ----------------------------------------------------------------- Named tuples assign meaning to each position in a tuple and allow for more readable, self-documenting code. They can be used wherever regular tuples are used, and they add the ability to access fields by name instead of position index. -.. function:: named_tuple(typename, fieldnames, [verbose]) +.. function:: namedtuple(typename, fieldnames, [verbose]) Returns a new tuple subclass named *typename*. The new subclass is used to create tuple-like objects that have fields accessable by attribute lookup as @@ -415,7 +415,7 @@ they add the ability to access fields by name instead of position index. Example:: - >>> Point = named_tuple('Point', 'x y', verbose=True) + >>> Point = namedtuple('Point', 'x y', verbose=True) class Point(tuple): 'Point(x, y)' __slots__ = () @@ -428,8 +428,8 @@ Example:: 'Return a new dict mapping field names to their values' return dict(zip(('x', 'y'), self)) def __replace__(self, field, value): - 'Return a new Point object replacing one field with a new value' - return Point(**dict(zip(('x', 'y'), self) + [(field, value)])) + 'Return a new Point object replacing specified fields with new values' + return Point(**dict(zip(('x', 'y'), self) + kwds.items())) x = property(itemgetter(0)) y = property(itemgetter(1)) @@ -447,7 +447,7 @@ Example:: Named tuples are especially useful for assigning field names to result tuples returned by the :mod:`csv` or :mod:`sqlite3` modules:: - EmployeeRecord = named_tuple('EmployeeRecord', 'name, age, title, department, paygrade') + EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade') from itertools import starmap import csv @@ -486,18 +486,18 @@ two additonal methods and a read-only attribute. >>> p.__asdict__() {'x': 11, 'y': 22} -.. method:: somenamedtuple.__replace__(field, value) +.. method:: somenamedtuple.__replace__(kwargs) - Return a new instance of the named tuple replacing the named *field* with a new *value*: + Return a new instance of the named tuple replacing specified fields with new values: :: >>> p = Point(x=11, y=22) - >>> p.__replace__('x', 33) + >>> p.__replace__(x=33) Point(x=33, y=22) - >>> for recordnum, record in inventory: - ... inventory[recordnum] = record.replace('total', record.price * record.quantity) + >>> for partnum, record in inventory.items(): + ... inventory[partnum] = record.__replace__(price=newprices[partnum], updated=time.now()) .. attribute:: somenamedtuple.__fields__ @@ -509,11 +509,31 @@ two additonal methods and a read-only attribute. >>> p.__fields__ # view the field names ('x', 'y') - >>> Color = named_tuple('Color', 'red green blue') - >>> Pixel = named_tuple('Pixel', Point.__fields__ + Color.__fields__) + >>> Color = namedtuple('Color', 'red green blue') + >>> Pixel = namedtuple('Pixel', Point.__fields__ + Color.__fields__) >>> Pixel(11, 22, 128, 255, 0) Pixel(x=11, y=22, red=128, green=255, blue=0)' +Since a named tuple is a regular Python class, it is easy to add or change +functionality. For example, the display format can be changed by overriding +the :meth:`__repr__` method: + +:: + + >>> Point = namedtuple('Point', 'x y') + >>> Point.__repr__ = lambda self: 'Point(%.3f, %.3f)' % self + >>> Point(x=10, y=20) + Point(10.000, 20.000) + +Default values can be implemented by starting with a prototype instance +and customizing it with :meth:`__replace__`: + +:: + + >>> Account = namedtuple('Account', 'owner balance transaction_count') + >>> model_account = Account('', 0.0, 0) + >>> johns_account = model_account.__replace__(owner='John') + .. rubric:: Footnotes .. [#] For information on the star-operator see diff --git a/Doc/library/random.rst b/Doc/library/random.rst index f0d5d1214af..9b020034849 100644 --- a/Doc/library/random.rst +++ b/Doc/library/random.rst @@ -282,8 +282,3 @@ Examples of basic usage:: Wichmann, B. A. & Hill, I. D., "Algorithm AS 183: An efficient and portable pseudo-random number generator", Applied Statistics 31 (1982) 188-190. - http://www.npl.co.uk/ssfm/download/abstracts.html#196 - A modern variation of the Wichmann-Hill generator that greatly increases the - period, and passes now-standard statistical tests that the original generator - failed. - diff --git a/Lib/collections.py b/Lib/collections.py index 90ed7766fa8..7b23948c66b 100644 --- a/Lib/collections.py +++ b/Lib/collections.py @@ -30,7 +30,7 @@ def namedtuple(typename, field_names, verbose=False): 11 >>> Point(**d) # convert from a dictionary Point(x=11, y=22) - >>> p.__replace__('x', 100) # __replace__() is like str.replace() but targets a named field + >>> p.__replace__(x=100) # __replace__() is like str.replace() but targets named fields Point(x=100, y=22) """ @@ -60,7 +60,7 @@ def namedtuple(typename, field_names, verbose=False): template = '''class %(typename)s(tuple): '%(typename)s(%(argtxt)s)' __slots__ = () - __fields__ = %(field_names)r + __fields__ = property(lambda self: %(field_names)r) def __new__(cls, %(argtxt)s): return tuple.__new__(cls, (%(argtxt)s)) def __repr__(self): @@ -68,9 +68,9 @@ def namedtuple(typename, field_names, verbose=False): def __asdict__(self, dict=dict, zip=zip): 'Return a new dict mapping field names to their values' return dict(zip(%(field_names)r, self)) - def __replace__(self, field, value, dict=dict, zip=zip): - 'Return a new %(typename)s object replacing one field with a new value' - return %(typename)s(**dict(list(zip(%(field_names)r, self)) + [(field, value)])) \n''' % locals() + def __replace__(self, **kwds): + 'Return a new %(typename)s object replacing specified fields with new values' + return %(typename)s(**dict(zip(%(field_names)r, self) + kwds.items())) \n''' % locals() for i, name in enumerate(field_names): template += ' %s = property(itemgetter(%d))\n' % (name, i) if verbose: @@ -103,6 +103,10 @@ if __name__ == '__main__': p = Point(x=10, y=20) assert p == loads(dumps(p)) + # test and demonstrate ability to override methods + Point.__repr__ = lambda self: 'Point(%.3f, %.3f)' % self + print p + import doctest TestResults = namedtuple('TestResults', 'failed attempted') print(TestResults(*doctest.testmod())) diff --git a/Lib/test/seq_tests.py b/Lib/test/seq_tests.py index eb6d141aa56..ebd6157ced6 100644 --- a/Lib/test/seq_tests.py +++ b/Lib/test/seq_tests.py @@ -304,6 +304,13 @@ class CommonTest(unittest.TestCase): self.assertEqual(self.type2test(s)*(-4), self.type2test([])) self.assertEqual(id(s), id(s*1)) + def test_bigrepeat(self): + x = self.type2test([0]) + x *= 2**16 + self.assertRaises(MemoryError, x.__mul__, 2**16) + if hasattr(x, '__imul__'): + self.assertRaises(MemoryError, x.__imul__, 2**16) + def test_subscript(self): a = self.type2test([10, 11]) self.assertEqual(a.__getitem__(0), 10) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index 86b47ded4d3..0243134a84a 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -48,9 +48,17 @@ class TestNamedTuple(unittest.TestCase): self.assert_('__dict__' not in dir(p)) # verify instance has no dict self.assert_('__weakref__' not in dir(p)) self.assertEqual(p.__fields__, ('x', 'y')) # test __fields__ attribute - self.assertEqual(p.__replace__('x', 1), (1, 22)) # test __replace__ method + self.assertEqual(p.__replace__(x=1), (1, 22)) # test __replace__ method self.assertEqual(p.__asdict__(), dict(x=11, y=22)) # test __dict__ method + # Verify that __fields__ is read-only + try: + p.__fields__ = ('F1' ,'F2') + except AttributeError: + pass + else: + self.fail('The __fields__ attribute needs to be read-only') + # verify that field string can have commas Point = namedtuple('Point', 'x, y') p = Point(x=11, y=22) diff --git a/Modules/readline.c b/Modules/readline.c index 90529376b61..c915327ad26 100644 --- a/Modules/readline.c +++ b/Modules/readline.c @@ -59,8 +59,7 @@ parse_and_bind(PyObject *self, PyObject *args) strcpy(copy, s); rl_parse_and_bind(copy); free(copy); /* Free the copy */ - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_parse_and_bind, @@ -79,8 +78,7 @@ read_init_file(PyObject *self, PyObject *args) errno = rl_read_init_file(s); if (errno) return PyErr_SetFromErrno(PyExc_IOError); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_read_init_file, @@ -100,8 +98,7 @@ read_history_file(PyObject *self, PyObject *args) errno = read_history(s); if (errno) return PyErr_SetFromErrno(PyExc_IOError); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static int _history_length = -1; /* do not truncate history by default */ @@ -124,8 +121,7 @@ write_history_file(PyObject *self, PyObject *args) history_truncate_file(s, _history_length); if (errno) return PyErr_SetFromErrno(PyExc_IOError); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_write_history_file, @@ -143,8 +139,7 @@ set_history_length(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "i:set_history_length", &length)) return NULL; _history_length = length; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(set_history_length_doc, @@ -195,8 +190,7 @@ set_hook(const char *funcname, PyObject **hook_var, PyObject *args) PyErr_SetString(PyExc_TypeError, buf); return NULL; } - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } @@ -218,7 +212,7 @@ set_completion_display_matches_hook(PyObject *self, PyObject *args) /* We cannot set this hook globally, since it replaces the default completion display. */ rl_completion_display_matches_hook = - completion_display_matches_hook ? + completion_display_matches_hook ? (rl_compdisp_func_t *)on_completion_display_matches_hook : 0; #endif return result; @@ -325,8 +319,7 @@ set_completer_delims(PyObject *self, PyObject *args) } free((void*)rl_completer_word_break_characters); rl_completer_word_break_characters = strdup(break_chars); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_set_completer_delims, @@ -336,32 +329,31 @@ set the readline word delimiters for tab-completion"); static PyObject * py_remove_history(PyObject *self, PyObject *args) { - int entry_number; - HIST_ENTRY *entry; + int entry_number; + HIST_ENTRY *entry; - if (!PyArg_ParseTuple(args, "i:remove_history", &entry_number)) - return NULL; - if (entry_number < 0) { - PyErr_SetString(PyExc_ValueError, - "History index cannot be negative"); - return NULL; - } - entry = remove_history(entry_number); - if (!entry) { - PyErr_Format(PyExc_ValueError, - "No history item at position %d", - entry_number); - return NULL; - } - /* free memory allocated for the history entry */ - if (entry->line) - free(entry->line); - if (entry->data) - free(entry->data); - free(entry); + if (!PyArg_ParseTuple(args, "i:remove_history", &entry_number)) + return NULL; + if (entry_number < 0) { + PyErr_SetString(PyExc_ValueError, + "History index cannot be negative"); + return NULL; + } + entry = remove_history(entry_number); + if (!entry) { + PyErr_Format(PyExc_ValueError, + "No history item at position %d", + entry_number); + return NULL; + } + /* free memory allocated for the history entry */ + if (entry->line) + free(entry->line); + if (entry->data) + free(entry->data); + free(entry); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_remove_history, @@ -371,34 +363,34 @@ remove history item given by its position"); static PyObject * py_replace_history(PyObject *self, PyObject *args) { - int entry_number; - char *line; - HIST_ENTRY *old_entry; + int entry_number; + char *line; + HIST_ENTRY *old_entry; - if (!PyArg_ParseTuple(args, "is:replace_history", &entry_number, &line)) { - return NULL; - } - if (entry_number < 0) { - PyErr_SetString(PyExc_ValueError, - "History index cannot be negative"); - return NULL; - } - old_entry = replace_history_entry(entry_number, line, (void *)NULL); - if (!old_entry) { - PyErr_Format(PyExc_ValueError, - "No history item at position %d", - entry_number); - return NULL; - } - /* free memory allocated for the old history entry */ - if (old_entry->line) - free(old_entry->line); - if (old_entry->data) - free(old_entry->data); - free(old_entry); + if (!PyArg_ParseTuple(args, "is:replace_history", &entry_number, + &line)) { + return NULL; + } + if (entry_number < 0) { + PyErr_SetString(PyExc_ValueError, + "History index cannot be negative"); + return NULL; + } + old_entry = replace_history_entry(entry_number, line, (void *)NULL); + if (!old_entry) { + PyErr_Format(PyExc_ValueError, + "No history item at position %d", + entry_number); + return NULL; + } + /* free memory allocated for the old history entry */ + if (old_entry->line) + free(old_entry->line); + if (old_entry->data) + free(old_entry->data); + free(old_entry); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_replace_history, @@ -416,8 +408,7 @@ py_add_history(PyObject *self, PyObject *args) return NULL; } add_history(line); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_add_history, @@ -458,8 +449,7 @@ static PyObject * get_completer(PyObject *self, PyObject *noargs) { if (completer == NULL) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } Py_INCREF(completer); return completer; @@ -483,8 +473,7 @@ get_history_item(PyObject *self, PyObject *args) if ((hist_ent = history_get(idx))) return PyUnicode_FromString(hist_ent->line); else { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } } @@ -530,8 +519,7 @@ static PyObject * py_clear_history(PyObject *self, PyObject *noarg) { clear_history(); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_clear_history, @@ -549,8 +537,7 @@ insert_text(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "s:insert_text", &s)) return NULL; rl_insert_text(s); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_insert_text, @@ -564,8 +551,7 @@ static PyObject * redisplay(PyObject *self, PyObject *noarg) { rl_redisplay(); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } PyDoc_STRVAR(doc_redisplay, @@ -591,9 +577,9 @@ static struct PyMethodDef readline_methods[] = METH_VARARGS, doc_get_history_item}, {"get_current_history_length", (PyCFunction)get_current_history_length, METH_NOARGS, doc_get_current_history_length}, - {"set_history_length", set_history_length, + {"set_history_length", set_history_length, METH_VARARGS, set_history_length_doc}, - {"get_history_length", get_history_length, + {"get_history_length", get_history_length, METH_NOARGS, get_history_length_doc}, {"set_completer", set_completer, METH_VARARGS, doc_set_completer}, {"get_completer", get_completer, METH_NOARGS, doc_get_completer}, @@ -605,8 +591,8 @@ static struct PyMethodDef readline_methods[] = {"set_completer_delims", set_completer_delims, METH_VARARGS, doc_set_completer_delims}, {"add_history", py_add_history, METH_VARARGS, doc_add_history}, - {"remove_history_item", py_remove_history, METH_VARARGS, doc_remove_history}, - {"replace_history_item", py_replace_history, METH_VARARGS, doc_replace_history}, + {"remove_history_item", py_remove_history, METH_VARARGS, doc_remove_history}, + {"replace_history_item", py_replace_history, METH_VARARGS, doc_replace_history}, {"get_completer_delims", get_completer_delims, METH_NOARGS, doc_get_completer_delims}, @@ -633,7 +619,7 @@ on_hook(PyObject *func) int result = 0; if (func != NULL) { PyObject *r; -#ifdef WITH_THREAD +#ifdef WITH_THREAD PyGILState_STATE gilstate = PyGILState_Ensure(); #endif r = PyObject_CallFunction(func, NULL); @@ -652,7 +638,7 @@ on_hook(PyObject *func) PyErr_Clear(); Py_XDECREF(r); done: -#ifdef WITH_THREAD +#ifdef WITH_THREAD PyGILState_Release(gilstate); #endif return result; @@ -682,37 +668,37 @@ on_completion_display_matches_hook(char **matches, int num_matches, int max_length) { int i; - PyObject *m, *s; - PyObject *r; + PyObject *m=NULL, *s=NULL, *r=NULL; #ifdef WITH_THREAD PyGILState_STATE gilstate = PyGILState_Ensure(); #endif m = PyList_New(num_matches); + if (m == NULL) + goto error; for (i = 0; i < num_matches; i++) { s = PyUnicode_FromString(matches[i+1]); - if (s) { - PyList_SetItem(m, i, s); - } - else { + if (s == NULL) + goto error; + if (PyList_SetItem(m, i, s) == -1) goto error; - } } r = PyObject_CallFunction(completion_display_matches_hook, "sOi", matches[0], m, max_length); Py_DECREF(m), m=NULL; - + if (r == NULL || (r != Py_None && PyInt_AsLong(r) == -1 && PyErr_Occurred())) { goto error; } + Py_XDECREF(r), r=NULL; - Py_DECREF(r); - goto done; - error: - PyErr_Clear(); - Py_XDECREF(r); - done: + if (0) { + error: + PyErr_Clear(); + Py_XDECREF(m); + Py_XDECREF(r); + } #ifdef WITH_THREAD PyGILState_Release(gilstate); #endif diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 2621a9eb72e..30e8d227121 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -450,87 +450,11 @@ set_error(void) { #ifdef MS_WINDOWS int err_no = WSAGetLastError(); - static struct { - int no; - const char *msg; - } *msgp, msgs[] = { - {WSAEINTR, "Interrupted system call"}, - {WSAEBADF, "Bad file descriptor"}, - {WSAEACCES, "Permission denied"}, - {WSAEFAULT, "Bad address"}, - {WSAEINVAL, "Invalid argument"}, - {WSAEMFILE, "Too many open files"}, - {WSAEWOULDBLOCK, - "The socket operation could not complete " - "without blocking"}, - {WSAEINPROGRESS, "Operation now in progress"}, - {WSAEALREADY, "Operation already in progress"}, - {WSAENOTSOCK, "Socket operation on non-socket"}, - {WSAEDESTADDRREQ, "Destination address required"}, - {WSAEMSGSIZE, "Message too long"}, - {WSAEPROTOTYPE, "Protocol wrong type for socket"}, - {WSAENOPROTOOPT, "Protocol not available"}, - {WSAEPROTONOSUPPORT, "Protocol not supported"}, - {WSAESOCKTNOSUPPORT, "Socket type not supported"}, - {WSAEOPNOTSUPP, "Operation not supported"}, - {WSAEPFNOSUPPORT, "Protocol family not supported"}, - {WSAEAFNOSUPPORT, "Address family not supported"}, - {WSAEADDRINUSE, "Address already in use"}, - {WSAEADDRNOTAVAIL, "Can't assign requested address"}, - {WSAENETDOWN, "Network is down"}, - {WSAENETUNREACH, "Network is unreachable"}, - {WSAENETRESET, "Network dropped connection on reset"}, - {WSAECONNABORTED, "Software caused connection abort"}, - {WSAECONNRESET, "Connection reset by peer"}, - {WSAENOBUFS, "No buffer space available"}, - {WSAEISCONN, "Socket is already connected"}, - {WSAENOTCONN, "Socket is not connected"}, - {WSAESHUTDOWN, "Can't send after socket shutdown"}, - {WSAETOOMANYREFS, "Too many references: can't splice"}, - {WSAETIMEDOUT, "Operation timed out"}, - {WSAECONNREFUSED, "Connection refused"}, - {WSAELOOP, "Too many levels of symbolic links"}, - {WSAENAMETOOLONG, "File name too long"}, - {WSAEHOSTDOWN, "Host is down"}, - {WSAEHOSTUNREACH, "No route to host"}, - {WSAENOTEMPTY, "Directory not empty"}, - {WSAEPROCLIM, "Too many processes"}, - {WSAEUSERS, "Too many users"}, - {WSAEDQUOT, "Disc quota exceeded"}, - {WSAESTALE, "Stale NFS file handle"}, - {WSAEREMOTE, "Too many levels of remote in path"}, - {WSASYSNOTREADY, "Network subsystem is unvailable"}, - {WSAVERNOTSUPPORTED, "WinSock version is not supported"}, - {WSANOTINITIALISED, - "Successful WSAStartup() not yet performed"}, - {WSAEDISCON, "Graceful shutdown in progress"}, - /* Resolver errors */ - {WSAHOST_NOT_FOUND, "No such host is known"}, - {WSATRY_AGAIN, "Host not found, or server failed"}, - {WSANO_RECOVERY, "Unexpected server error encountered"}, - {WSANO_DATA, "Valid name without requested data"}, - {WSANO_ADDRESS, "No address, look for MX record"}, - {0, NULL} - }; - if (err_no) { - PyObject *v; - const char *msg = "winsock error"; - - for (msgp = msgs; msgp->msg; msgp++) { - if (err_no == msgp->no) { - msg = msgp->msg; - break; - } - } - - v = Py_BuildValue("(is)", err_no, msg); - if (v != NULL) { - PyErr_SetObject(socket_error, v); - Py_DECREF(v); - } - return NULL; - } - else + /* PyErr_SetExcFromWindowsErr() invokes FormatMessage() which + recognizes the error codes used by both GetLastError() and + WSAGetLastError */ + if (err_no) + return PyErr_SetExcFromWindowsErr(socket_error, err_no); #endif #if defined(PYOS_OS2) && !defined(PYCC_GCC)