From 8ce81f767a48e9e645c523137c7f83e49f79f986 Mon Sep 17 00:00:00 2001 From: Thomas Wouters Date: Thu, 20 Sep 2007 18:22:40 +0000 Subject: Merged revisions 58211-58220 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r58211 | facundo.batista | 2007-09-19 19:53:25 +0200 (Wed, 19 Sep 2007) | 4 lines Issue #1772851. Optimization of __hash__ to behave better for big big numbers. ........ r58216 | raymond.hettinger | 2007-09-20 05:03:43 +0200 (Thu, 20 Sep 2007) | 1 line Fit nits ........ r58217 | georg.brandl | 2007-09-20 10:44:59 +0200 (Thu, 20 Sep 2007) | 2 lines alternate -> alternative. ........ r58218 | georg.brandl | 2007-09-20 18:06:07 +0200 (Thu, 20 Sep 2007) | 2 lines Patch #1541463: optimize performance of cgi.FieldStorage operations. ........ r58219 | georg.brandl | 2007-09-20 18:45:27 +0200 (Thu, 20 Sep 2007) | 2 lines #1176: document that string methods don't take keyword args. ........ r58220 | thomas.wouters | 2007-09-20 19:35:10 +0200 (Thu, 20 Sep 2007) | 4 lines Try harder to stay within the 79-column limit. There's still two places that go (way) over, but those are harder to fix without suffering in readability. ........ --- Doc/library/collections.rst | 18 ++++++---- Doc/library/decimal.rst | 2 +- Doc/library/stdtypes.rst | 11 +++--- Doc/tutorial/inputoutput.rst | 2 +- Lib/cgi.py | 12 +++---- Lib/decimal.py | 15 +++++--- Lib/test/test_decimal.py | 32 +++++++++++++++++ Python/ceval.c | 86 +++++++++++++++++++++++++------------------- 8 files changed, 117 insertions(+), 61 deletions(-) diff --git a/Doc/library/collections.rst b/Doc/library/collections.rst index 227f721..274ca15 100644 --- a/Doc/library/collections.rst +++ b/Doc/library/collections.rst @@ -395,8 +395,8 @@ Setting the :attr:`default_factory` to :class:`set` makes the .. _named-tuple-factory: -:func:`NamedTuple` factory function ------------------------------------ +: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 @@ -411,12 +411,12 @@ they add the ability to access fields by name instead of position index. method which lists the tuple contents in a ``name=value`` format. The *fieldnames* are specified in a single string with each fieldname separated by - a space and/or comma. Any valid Python identifier may be used for a field name. + a space and/or comma. Any valid Python identifier may be used for a fieldname. - If *verbose* is true, the *NamedTuple* call will print the class definition. + If *verbose* is true, will print the class definition. *NamedTuple* instances do not have per-instance dictionaries, so they are - lightweight, requiring no more memory than regular tuples. + lightweight and require no more memory than regular tuples. Example:: @@ -467,7 +467,9 @@ an additonal method and an informational read-only attribute. .. method:: somenamedtuple.replace(field, value) - 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 the named *field* with a new *value*: + +:: >>> p = Point(x=11, y=22) >>> p.__replace__('x', 33) @@ -480,7 +482,9 @@ an additonal method and an informational read-only attribute. Return a tuple of strings listing the field names. This is useful for introspection, for converting a named tuple instance to a dictionary, and for combining named tuple - types to create new named tuple types:: + types to create new named tuple types: + +:: >>> p.__fields__ # view the field names ('x', 'y') diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst index bbac0d4..ee4aeec 100644 --- a/Doc/library/decimal.rst +++ b/Doc/library/decimal.rst @@ -977,7 +977,7 @@ method. For example, ``C.exp(x)`` is equivalent to The usual approach to working with decimals is to create :class:`Decimal` instances and then apply arithmetic operations which take place within the -current context for the active thread. An alternate approach is to use context +current context for the active thread. An alternative approach is to use context methods for calculating within a specific context. The methods are similar to those for the :class:`Decimal` class and are only briefly recounted here. diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 75db75c..1a0bdf3 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -657,10 +657,13 @@ String Methods .. index:: pair: string; methods -String objects support the methods listed below. In addition, Python's strings -support the sequence type methods described in the :ref:`typesseq` section. To -output formatted strings, see the :ref:`string-formatting` section. Also, see -the :mod:`re` module for string functions based on regular expressions. +String objects support the methods listed below. Note that none of these +methods take keyword arguments. + +In addition, Python's strings support the sequence type methods described in +the :ref:`typesseq` section. To output formatted strings, see the +:ref:`string-formatting` section. Also, see the :mod:`re` module for string +functions based on regular expressions. .. method:: str.capitalize() diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index 54f4403..2f4cdd3 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -252,7 +252,7 @@ having to load the entire file in memory. Only complete lines will be returned. >>> f.readlines() ['This is the first line of the file.\n', 'Second line of the file\n'] -An alternate approach to reading lines is to loop over the file object. This is +An alternative approach to reading lines is to loop over the file object. This is memory efficient, fast, and leads to simpler code:: >>> for line in f: diff --git a/Lib/cgi.py b/Lib/cgi.py index 7b457cc..cb92cfc 100755 --- a/Lib/cgi.py +++ b/Lib/cgi.py @@ -604,23 +604,21 @@ class FieldStorage: """Dictionary style keys() method.""" if self.list is None: raise TypeError("not indexable") - keys = [] - for item in self.list: - if item.name not in keys: keys.append(item.name) - return keys + return list(set(item.name for item in self.list)) def __contains__(self, key): """Dictionary style __contains__ method.""" if self.list is None: raise TypeError("not indexable") - for item in self.list: - if item.name == key: return True - return False + return any(item.name == key for item in self.list) def __len__(self): """Dictionary style len(x) support.""" return len(self.keys()) + def __nonzero__(self): + return bool(self.list) + def read_urlencoded(self): """Internal: read data in query string format.""" qs = self.fp.read(self.length) diff --git a/Lib/decimal.py b/Lib/decimal.py index d7bd127..ffe6e9e 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -786,10 +786,17 @@ class Decimal(object): if self._isnan(): raise TypeError('Cannot hash a NaN value.') return hash(str(self)) - i = int(self) - if self == Decimal(i): - return hash(i) - assert self.__bool__() # '-0' handled by integer case + if not self: + return 0 + if self._isinteger(): + op = _WorkRep(self.to_integral_value()) + # to make computation feasible for Decimals with large + # exponent, we use the fact that hash(n) == hash(m) for + # any two nonzero integers n and m such that (i) n and m + # have the same sign, and (ii) n is congruent to m modulo + # 2**64-1. So we can replace hash((-1)**s*c*10**e) with + # hash((-1)**s*c*pow(10, e, 2**64-1). + return hash((-1)**op.sign*op.int*pow(10, op.exp, 2**64-1)) return hash(str(self.normalize())) def as_tuple(self): diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 41d1dd5..513ba16 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -901,6 +901,38 @@ class DecimalUsabilityTest(unittest.TestCase): def test_hash_method(self): #just that it's hashable hash(Decimal(23)) + + test_values = [Decimal(sign*(2**m + n)) + for m in [0, 14, 15, 16, 17, 30, 31, + 32, 33, 62, 63, 64, 65, 66] + for n in range(-10, 10) + for sign in [-1, 1]] + test_values.extend([ + Decimal("-0"), # zeros + Decimal("0.00"), + Decimal("-0.000"), + Decimal("0E10"), + Decimal("-0E12"), + Decimal("10.0"), # negative exponent + Decimal("-23.00000"), + Decimal("1230E100"), # positive exponent + Decimal("-4.5678E50"), + # a value for which hash(n) != hash(n % (2**64-1)) + # in Python pre-2.6 + Decimal(2**64 + 2**32 - 1), + # selection of values which fail with the old (before + # version 2.6) long.__hash__ + Decimal("1.634E100"), + Decimal("90.697E100"), + Decimal("188.83E100"), + Decimal("1652.9E100"), + Decimal("56531E100"), + ]) + + # check that hash(d) == hash(int(d)) for integral values + for value in test_values: + self.assertEqual(hash(value), hash(int(value))) + #the same hash that to an int self.assertEqual(hash(Decimal(23)), hash(23)) self.assertRaises(TypeError, hash, Decimal('NaN')) diff --git a/Python/ceval.c b/Python/ceval.c index 73a0624..dd6f6c4 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -28,8 +28,9 @@ typedef unsigned long long uint64; #if defined(__ppc__) /* <- Don't know if this is the correct symbol; this - section should work for GCC on any PowerPC platform, - irrespective of OS. POWER? Who knows :-) */ + section should work for GCC on any PowerPC + platform, irrespective of OS. + POWER? Who knows :-) */ #define READ_TIMESTAMP(var) ppc_getcounter(&var) @@ -93,7 +94,8 @@ static PyObject * call_function(PyObject ***, int); static PyObject * fast_function(PyObject *, PyObject ***, int, int, int); static PyObject * do_call(PyObject *, PyObject ***, int, int); static PyObject * ext_do_call(PyObject *, PyObject ***, int, int, int); -static PyObject * update_keyword_args(PyObject *, int, PyObject ***,PyObject *); +static PyObject * update_keyword_args(PyObject *, int, PyObject ***, + PyObject *); static PyObject * update_star_args(int, int, PyObject *, PyObject ***); static PyObject * load_args(PyObject ***, int); #define CALL_FLAG_VAR 1 @@ -509,7 +511,8 @@ PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals) PyObject * PyEval_EvalFrame(PyFrameObject *f) { /* This is for backward compatibility with extension modules that - used this API; core interpreter code should call PyEval_EvalFrameEx() */ + used this API; core interpreter code should call + PyEval_EvalFrameEx() */ return PyEval_EvalFrameEx(f, 0); } @@ -519,7 +522,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) #ifdef DXPAIRS int lastopcode = 0; #endif - register PyObject **stack_pointer; /* Next free slot in value stack */ + register PyObject **stack_pointer; /* Next free slot in value stack */ register unsigned char *next_instr; register int opcode; /* Current opcode */ register int oparg; /* Current opcode argument, if any */ @@ -610,10 +613,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) #define JUMPBY(x) (next_instr += (x)) /* OpCode prediction macros - Some opcodes tend to come in pairs thus making it possible to predict - the second code when the first is run. For example, COMPARE_OP is often - followed by JUMP_IF_FALSE or JUMP_IF_TRUE. And, those opcodes are often - followed by a POP_TOP. + Some opcodes tend to come in pairs thus making it possible to + predict the second code when the first is run. For example, + COMPARE_OP is often followed by JUMP_IF_FALSE or JUMP_IF_TRUE. And, + those opcodes are often followed by a POP_TOP. Verifying the prediction costs a single high-speed test of register variable against a constant. If the pairing was good, then the @@ -660,11 +663,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) #define PUSH(v) { (void)(BASIC_PUSH(v), \ lltrace && prtrace(TOP(), "push")); \ assert(STACK_LEVEL() <= co->co_stacksize); } -#define POP() ((void)(lltrace && prtrace(TOP(), "pop")), BASIC_POP()) +#define POP() ((void)(lltrace && prtrace(TOP(), "pop")), \ + BASIC_POP()) #define STACKADJ(n) { (void)(BASIC_STACKADJ(n), \ lltrace && prtrace(TOP(), "stackadj")); \ assert(STACK_LEVEL() <= co->co_stacksize); } -#define EXT_POP(STACK_POINTER) (lltrace && prtrace((STACK_POINTER)[-1], "ext_pop"), *--(STACK_POINTER)) +#define EXT_POP(STACK_POINTER) (lltrace && prtrace((STACK_POINTER)[-1], \ + "ext_pop"), *--(STACK_POINTER)) #else #define PUSH(v) BASIC_PUSH(v) #define POP() BASIC_POP() @@ -1568,7 +1573,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) if ((x = f->f_locals) != NULL) { if ((err = PyObject_DelItem(x, w)) != 0) format_exc_check_arg(PyExc_NameError, - NAME_ERROR_MSG ,w); + NAME_ERROR_MSG, + w); break; } PyErr_Format(PyExc_SystemError, @@ -1579,8 +1585,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) PREDICTED_WITH_ARG(UNPACK_SEQUENCE); case UNPACK_SEQUENCE: v = POP(); - if (PyTuple_CheckExact(v) && PyTuple_GET_SIZE(v) == oparg) { - PyObject **items = ((PyTupleObject *)v)->ob_item; + if (PyTuple_CheckExact(v) && + PyTuple_GET_SIZE(v) == oparg) { + PyObject **items = \ + ((PyTupleObject *)v)->ob_item; while (oparg--) { w = items[oparg]; Py_INCREF(w); @@ -1588,15 +1596,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) } Py_DECREF(v); continue; - } else if (PyList_CheckExact(v) && PyList_GET_SIZE(v) == oparg) { - PyObject **items = ((PyListObject *)v)->ob_item; + } else if (PyList_CheckExact(v) && + PyList_GET_SIZE(v) == oparg) { + PyObject **items = \ + ((PyListObject *)v)->ob_item; while (oparg--) { w = items[oparg]; Py_INCREF(w); PUSH(w); } } else if (unpack_iterable(v, oparg, -1, - stack_pointer + oparg)) { + stack_pointer + oparg)) { stack_pointer += oparg; } else { /* unpack_iterable() raised an exception */ @@ -1669,7 +1679,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) else { x = PyObject_GetItem(v, w); if (x == NULL && PyErr_Occurred()) { - if (!PyErr_ExceptionMatches(PyExc_KeyError)) + if (!PyErr_ExceptionMatches( + PyExc_KeyError)) break; PyErr_Clear(); } @@ -1681,7 +1692,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) if (x == NULL) { format_exc_check_arg( PyExc_NameError, - NAME_ERROR_MSG ,w); + NAME_ERROR_MSG, w); break; } } @@ -1782,13 +1793,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) UNBOUNDLOCAL_ERROR_MSG, v); } else { - v = PyTuple_GET_ITEM( - co->co_freevars, - oparg - PyTuple_GET_SIZE(co->co_cellvars)); - format_exc_check_arg( - PyExc_NameError, - UNBOUNDFREE_ERROR_MSG, - v); + v = PyTuple_GET_ITEM(co->co_freevars, oparg - + PyTuple_GET_SIZE(co->co_cellvars)); + format_exc_check_arg(PyExc_NameError, + UNBOUNDFREE_ERROR_MSG, v); } break; @@ -2046,7 +2054,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) continue; } if (PyErr_Occurred()) { - if (!PyErr_ExceptionMatches(PyExc_StopIteration)) + if (!PyErr_ExceptionMatches( + PyExc_StopIteration)) break; PyErr_Clear(); } @@ -2072,9 +2081,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) case SETUP_LOOP: case SETUP_EXCEPT: case SETUP_FINALLY: - /* NOTE: If you add any new block-setup opcodes that are - not try/except/finally handlers, you may need to - update the PyGen_NeedsFinalizing() function. */ + /* NOTE: If you add any new block-setup opcodes that + are not try/except/finally handlers, you may need + to update the PyGen_NeedsFinalizing() function. + */ PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, STACK_LEVEL()); @@ -3968,8 +3978,9 @@ string_concatenate(PyObject *v, PyObject *w, if (v->ob_refcnt == 2) { /* In the common case, there are 2 references to the value * stored in 'variable' when the += is performed: one on the - * value stack (in 'v') and one still stored in the 'variable'. - * We try to delete the variable now to reduce the refcnt to 1. + * value stack (in 'v') and one still stored in the + * 'variable'. We try to delete the variable now to reduce + * the refcnt to 1. */ switch (*next_instr) { case STORE_FAST: @@ -3982,7 +3993,8 @@ string_concatenate(PyObject *v, PyObject *w, } case STORE_DEREF: { - PyObject **freevars = f->f_localsplus + f->f_code->co_nlocals; + PyObject **freevars = (f->f_localsplus + + f->f_code->co_nlocals); PyObject *c = freevars[PEEKARG()]; if (PyCell_GET(c) == v) PyCell_Set(c, NULL); @@ -4010,10 +4022,10 @@ string_concatenate(PyObject *v, PyObject *w, */ if (_PyString_Resize(&v, new_len) != 0) { /* XXX if _PyString_Resize() fails, 'v' has been - * deallocated so it cannot be put back into 'variable'. - * The MemoryError is raised when there is no value in - * 'variable', which might (very remotely) be a cause - * of incompatibilities. + * deallocated so it cannot be put back into + * 'variable'. The MemoryError is raised when there + * is no value in 'variable', which might (very + * remotely) be a cause of incompatibilities. */ return NULL; } -- cgit v0.12