[Python-3000-checkins] r60476 - in python/branches/py3k: Doc/library/itertools.rst Doc/library/numbers.rst Lib/_abcoll.py Lib/numbers.py Lib/rational.py Objects/floatobject.c Python/import.c Python/marshal.c Python/sysmodule.c configure configure.in

christian.heimes python-3000-checkins at python.org
Thu Jan 31 15:31:46 CET 2008


Author: christian.heimes
Date: Thu Jan 31 15:31:45 2008
New Revision: 60476

Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Doc/library/itertools.rst
   python/branches/py3k/Doc/library/numbers.rst
   python/branches/py3k/Lib/_abcoll.py
   python/branches/py3k/Lib/numbers.py
   python/branches/py3k/Lib/rational.py
   python/branches/py3k/Objects/floatobject.c
   python/branches/py3k/Python/import.c
   python/branches/py3k/Python/marshal.c
   python/branches/py3k/Python/sysmodule.c
   python/branches/py3k/configure
   python/branches/py3k/configure.in
Log:
Merged revisions 60441-60474 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r60441 | christian.heimes | 2008-01-30 12:46:00 +0100 (Wed, 30 Jan 2008) | 1 line
  
  Removed unused var
........
  r60448 | christian.heimes | 2008-01-30 18:21:22 +0100 (Wed, 30 Jan 2008) | 1 line
  
  Fixed some references leaks in sys.
........
  r60450 | christian.heimes | 2008-01-30 19:58:29 +0100 (Wed, 30 Jan 2008) | 1 line
  
  The previous change was causing a segfault after multiple calls to Py_Initialize() and Py_Finalize().
........
  r60463 | raymond.hettinger | 2008-01-30 23:17:31 +0100 (Wed, 30 Jan 2008) | 1 line
  
  Update itertool recipes
........
  r60464 | christian.heimes | 2008-01-30 23:54:18 +0100 (Wed, 30 Jan 2008) | 1 line
  
  Bug #1234: Fixed semaphore errors on AIX 5.2
........
  r60469 | raymond.hettinger | 2008-01-31 02:38:15 +0100 (Thu, 31 Jan 2008) | 6 lines
  
  Fix defect in __ixor__ which would get the wrong
  answer if the input iterable had a duplicate element
  (two calls to toggle() reverse each other).  Borrow
  the correct code from sets.py.
........
  r60470 | raymond.hettinger | 2008-01-31 02:42:11 +0100 (Thu, 31 Jan 2008) | 1 line
  
  Missing return
........
  r60471 | jeffrey.yasskin | 2008-01-31 08:44:11 +0100 (Thu, 31 Jan 2008) | 4 lines
  
  Added more documentation on how mixed-mode arithmetic should be implemented. I
  also noticed and fixed a bug in Rational's forward operators (they were
  claiming all instances of numbers.Rational instead of just the concrete types).
........


Modified: python/branches/py3k/Doc/library/itertools.rst
==============================================================================
--- python/branches/py3k/Doc/library/itertools.rst	(original)
+++ python/branches/py3k/Doc/library/itertools.rst	Thu Jan 31 15:31:45 2008
@@ -511,5 +511,16 @@
        "grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
        return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)
 
-
+   def roundrobin(*iterables):
+       "roundrobin('abc', 'd', 'ef') --> 'a', 'd', 'e', 'b', 'f', 'c'"
+       # Recipe contributed by George Sakkis
+       pending = len(iterables)
+       nexts = cycle(iter(it).next for it in iterables)
+       while pending:
+           try:
+               for next in nexts:
+                   yield next()
+           except StopIteration:
+               pending -= 1
+               nexts = cycle(islice(nexts, pending))
 

Modified: python/branches/py3k/Doc/library/numbers.rst
==============================================================================
--- python/branches/py3k/Doc/library/numbers.rst	(original)
+++ python/branches/py3k/Doc/library/numbers.rst	Thu Jan 31 15:31:45 2008
@@ -97,3 +97,144 @@
    3-argument form of :func:`pow`, and the bit-string operations: ``<<``,
    ``>>``, ``&``, ``^``, ``|``, ``~``. Provides defaults for :func:`float`,
    :attr:`Rational.numerator`, and :attr:`Rational.denominator`.
+
+
+Notes for type implementors
+---------------------------
+
+Implementors should be careful to make equal numbers equal and hash
+them to the same values. This may be subtle if there are two different
+extensions of the real numbers. For example, :class:`rational.Rational`
+implements :func:`hash` as follows::
+
+    def __hash__(self):
+        if self.denominator == 1:
+            # Get integers right.
+            return hash(self.numerator)
+        # Expensive check, but definitely correct.
+        if self == float(self):
+            return hash(float(self))
+        else:
+            # Use tuple's hash to avoid a high collision rate on
+            # simple fractions.
+            return hash((self.numerator, self.denominator))
+
+
+Adding More Numeric ABCs
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are, of course, more possible ABCs for numbers, and this would
+be a poor hierarchy if it precluded the possibility of adding
+those. You can add ``MyFoo`` between :class:`Complex` and
+:class:`Real` with::
+
+    class MyFoo(Complex): ...
+    MyFoo.register(Real)
+
+
+Implementing the arithmetic operations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We want to implement the arithmetic operations so that mixed-mode
+operations either call an implementation whose author knew about the
+types of both arguments, or convert both to the nearest built in type
+and do the operation there. For subtypes of :class:`Integral`, this
+means that :meth:`__add__` and :meth:`__radd__` should be defined as::
+
+    class MyIntegral(Integral):
+
+        def __add__(self, other):
+            if isinstance(other, MyIntegral):
+                return do_my_adding_stuff(self, other)
+            elif isinstance(other, OtherTypeIKnowAbout):
+                return do_my_other_adding_stuff(self, other)
+            else:
+                return NotImplemented
+
+        def __radd__(self, other):
+            if isinstance(other, MyIntegral):
+                return do_my_adding_stuff(other, self)
+            elif isinstance(other, OtherTypeIKnowAbout):
+                return do_my_other_adding_stuff(other, self)
+            elif isinstance(other, Integral):
+                return int(other) + int(self)
+            elif isinstance(other, Real):
+                return float(other) + float(self)
+            elif isinstance(other, Complex):
+                return complex(other) + complex(self)
+            else:
+                return NotImplemented
+
+
+There are 5 different cases for a mixed-type operation on subclasses
+of :class:`Complex`. I'll refer to all of the above code that doesn't
+refer to ``MyIntegral`` and ``OtherTypeIKnowAbout`` as
+"boilerplate". ``a`` will be an instance of ``A``, which is a subtype
+of :class:`Complex` (``a : A <: Complex``), and ``b : B <:
+Complex``. I'll consider ``a + b``:
+
+    1. If ``A`` defines an :meth:`__add__` which accepts ``b``, all is
+       well.
+    2. If ``A`` falls back to the boilerplate code, and it were to
+       return a value from :meth:`__add__`, we'd miss the possibility
+       that ``B`` defines a more intelligent :meth:`__radd__`, so the
+       boilerplate should return :const:`NotImplemented` from
+       :meth:`__add__`. (Or ``A`` may not implement :meth:`__add__` at
+       all.)
+    3. Then ``B``'s :meth:`__radd__` gets a chance. If it accepts
+       ``a``, all is well.
+    4. If it falls back to the boilerplate, there are no more possible
+       methods to try, so this is where the default implementation
+       should live.
+    5. If ``B <: A``, Python tries ``B.__radd__`` before
+       ``A.__add__``. This is ok, because it was implemented with
+       knowledge of ``A``, so it can handle those instances before
+       delegating to :class:`Complex`.
+
+If ``A<:Complex`` and ``B<:Real`` without sharing any other knowledge,
+then the appropriate shared operation is the one involving the built
+in :class:`complex`, and both :meth:`__radd__` s land there, so ``a+b
+== b+a``.
+
+Because most of the operations on any given type will be very similar,
+it can be useful to define a helper function which generates the
+forward and reverse instances of any given operator. For example,
+:class:`rational.Rational` uses::
+
+    def _operator_fallbacks(monomorphic_operator, fallback_operator):
+        def forward(a, b):
+            if isinstance(b, (int, long, Rational)):
+                return monomorphic_operator(a, b)
+            elif isinstance(b, float):
+                return fallback_operator(float(a), b)
+            elif isinstance(b, complex):
+                return fallback_operator(complex(a), b)
+            else:
+                return NotImplemented
+        forward.__name__ = '__' + fallback_operator.__name__ + '__'
+        forward.__doc__ = monomorphic_operator.__doc__
+
+        def reverse(b, a):
+            if isinstance(a, RationalAbc):
+                # Includes ints.
+                return monomorphic_operator(a, b)
+            elif isinstance(a, numbers.Real):
+                return fallback_operator(float(a), float(b))
+            elif isinstance(a, numbers.Complex):
+                return fallback_operator(complex(a), complex(b))
+            else:
+                return NotImplemented
+        reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
+        reverse.__doc__ = monomorphic_operator.__doc__
+
+        return forward, reverse
+
+    def _add(a, b):
+        """a + b"""
+        return Rational(a.numerator * b.denominator +
+                        b.numerator * a.denominator,
+                        a.denominator * b.denominator)
+
+    __add__, __radd__ = _operator_fallbacks(_add, operator.add)
+
+    # ...
\ No newline at end of file

Modified: python/branches/py3k/Lib/_abcoll.py
==============================================================================
--- python/branches/py3k/Lib/_abcoll.py	(original)
+++ python/branches/py3k/Lib/_abcoll.py	Thu Jan 31 15:31:45 2008
@@ -300,16 +300,6 @@
         self.discard(value)
         return value
 
-    def toggle(self, value):
-        """Return True if it was added, False if deleted."""
-        # XXX This implementation is not thread-safe
-        if value in self:
-            self.discard(value)
-            return False
-        else:
-            self.add(value)
-            return True
-
     def clear(self):
         """This is slow (creates N new iterators!) but effective."""
         try:
@@ -330,9 +320,13 @@
         return self
 
     def __ixor__(self, it: Iterable):
-        # This calls toggle(), so if that is overridded, we call the override
+        if not isinstance(it, Set):
+            it = self._from_iterable(it)
         for value in it:
-            self.toggle(it)
+            if value in self:
+                self.discard(value)
+            else:
+                self.add(value)
         return self
 
     def __isub__(self, it: Iterable):

Modified: python/branches/py3k/Lib/numbers.py
==============================================================================
--- python/branches/py3k/Lib/numbers.py	(original)
+++ python/branches/py3k/Lib/numbers.py	Thu Jan 31 15:31:45 2008
@@ -291,7 +291,13 @@
 
     # Concrete implementation of Real's conversion to float.
     def __float__(self):
-        """float(self) = self.numerator / self.denominator"""
+        """float(self) = self.numerator / self.denominator
+
+        It's important that this conversion use the integer's "true"
+        division rather than casting one side to float before dividing
+        so that ratios of huge integers convert without overflowing.
+
+        """
         return self.numerator / self.denominator
 
 

Modified: python/branches/py3k/Lib/rational.py
==============================================================================
--- python/branches/py3k/Lib/rational.py	(original)
+++ python/branches/py3k/Lib/rational.py	Thu Jan 31 15:31:45 2008
@@ -178,16 +178,6 @@
         else:
             return '%s/%s' % (self.numerator, self.denominator)
 
-    """ XXX This section needs a lot more commentary
-
-    * Explain the typical sequence of checks, calls, and fallbacks.
-    * Explain the subtle reasons why this logic was needed.
-    * It is not clear how common cases are handled (for example, how
-      does the ratio of two huge integers get converted to a float
-      without overflowing the long-->float conversion.
-
-    """
-
     def _operator_fallbacks(monomorphic_operator, fallback_operator):
         """Generates forward and reverse operators given a purely-rational
         operator and a function from the operator module.
@@ -195,10 +185,82 @@
         Use this like:
         __op__, __rop__ = _operator_fallbacks(just_rational_op, operator.op)
 
+        In general, we want to implement the arithmetic operations so
+        that mixed-mode operations either call an implementation whose
+        author knew about the types of both arguments, or convert both
+        to the nearest built in type and do the operation there. In
+        Rational, that means that we define __add__ and __radd__ as:
+
+            def __add__(self, other):
+                if isinstance(other, (int, Rational)):
+                    # Do the real operation.
+                    return Rational(self.numerator * other.denominator +
+                                    other.numerator * self.denominator,
+                                    self.denominator * other.denominator)
+                # float and complex don't follow this protocol, and
+                # Rational knows about them, so special case them.
+                elif isinstance(other, float):
+                    return float(self) + other
+                elif isinstance(other, complex):
+                    return complex(self) + other
+                else:
+                    # Let the other type take over.
+                    return NotImplemented
+
+            def __radd__(self, other):
+                # radd handles more types than add because there's
+                # nothing left to fall back to.
+                if isinstance(other, RationalAbc):
+                    return Rational(self.numerator * other.denominator +
+                                    other.numerator * self.denominator,
+                                    self.denominator * other.denominator)
+                elif isinstance(other, Real):
+                    return float(other) + float(self)
+                elif isinstance(other, Complex):
+                    return complex(other) + complex(self)
+                else:
+                    return NotImplemented
+
+
+        There are 5 different cases for a mixed-type addition on
+        Rational. I'll refer to all of the above code that doesn't
+        refer to Rational, float, or complex as "boilerplate". 'r'
+        will be an instance of Rational, which is a subtype of
+        RationalAbc (r : Rational <: RationalAbc), and b : B <:
+        Complex. The first three involve 'r + b':
+
+            1. If B <: Rational, int, float, or complex, we handle
+               that specially, and all is well.
+            2. If Rational falls back to the boilerplate code, and it
+               were to return a value from __add__, we'd miss the
+               possibility that B defines a more intelligent __radd__,
+               so the boilerplate should return NotImplemented from
+               __add__. In particular, we don't handle RationalAbc
+               here, even though we could get an exact answer, in case
+               the other type wants to do something special.
+            3. If B <: Rational, Python tries B.__radd__ before
+               Rational.__add__. This is ok, because it was
+               implemented with knowledge of Rational, so it can
+               handle those instances before delegating to Real or
+               Complex.
+
+        The next two situations describe 'b + r'. We assume that b
+        didn't know about Rational in its implementation, and that it
+        uses similar boilerplate code:
+
+            4. If B <: RationalAbc, then __radd_ converts both to the
+               builtin rational type (hey look, that's us) and
+               proceeds.
+            5. Otherwise, __radd__ tries to find the nearest common
+               base ABC, and fall back to its builtin type. Since this
+               class doesn't subclass a concrete type, there's no
+               implementation to fall back to, so we need to try as
+               hard as possible to return an actual value, or the user
+               will get a TypeError.
+
         """
         def forward(a, b):
-            if isinstance(b, RationalAbc):
-                # Includes ints.
+            if isinstance(b, (int, Rational)):
                 return monomorphic_operator(a, b)
             elif isinstance(b, float):
                 return fallback_operator(float(a), b)

Modified: python/branches/py3k/Objects/floatobject.c
==============================================================================
--- python/branches/py3k/Objects/floatobject.c	(original)
+++ python/branches/py3k/Objects/floatobject.c	Thu Jan 31 15:31:45 2008
@@ -106,15 +106,9 @@
 PyObject *
 PyFloat_GetInfo(void)
 {
-	static PyObject* floatinfo;
+	PyObject* floatinfo;
 	int pos = 0;
 
-	if (floatinfo != NULL) {
-		Py_INCREF(floatinfo);
-		return floatinfo;
-	}
-	PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc);
-	
 	floatinfo = PyStructSequence_New(&FloatInfoType);
 	if (floatinfo == NULL) {
 		return NULL;
@@ -143,8 +137,6 @@
 		Py_CLEAR(floatinfo);
 		return NULL;
 	}
-
-	Py_INCREF(floatinfo);
 	return floatinfo;
 }
 
@@ -1601,6 +1593,9 @@
 	/* Initialize floating point repr */
 	_PyFloat_DigitsInit();
 #endif
+	/* Init float info */
+	if (FloatInfoType.tp_name == 0)
+		PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc);
 }
 
 void

Modified: python/branches/py3k/Python/import.c
==============================================================================
--- python/branches/py3k/Python/import.c	(original)
+++ python/branches/py3k/Python/import.c	Thu Jan 31 15:31:45 2008
@@ -371,6 +371,8 @@
 	"path", "argv", "ps1", "ps2",
 	"last_type", "last_value", "last_traceback",
 	"path_hooks", "path_importer_cache", "meta_path",
+	/* misc stuff */
+	"flags", "float_info",
 	NULL
 };
 

Modified: python/branches/py3k/Python/marshal.c
==============================================================================
--- python/branches/py3k/Python/marshal.c	(original)
+++ python/branches/py3k/Python/marshal.c	Thu Jan 31 15:31:45 2008
@@ -482,7 +482,7 @@
 {
 	/* NULL is a valid return value, it does not necessarily means that
 	   an exception is set. */
-	PyObject *v, *v2, *v3;
+	PyObject *v, *v2;
 	long i, n;
 	int type = r_byte(p);
 	PyObject *retval;

Modified: python/branches/py3k/Python/sysmodule.c
==============================================================================
--- python/branches/py3k/Python/sysmodule.c	(original)
+++ python/branches/py3k/Python/sysmodule.c	Thu Jan 31 15:31:45 2008
@@ -1131,8 +1131,6 @@
 	if (PyErr_Occurred()) {
 		return NULL;
 	}
-
-	Py_INCREF(seq);
 	return seq;
 }
 
@@ -1146,6 +1144,11 @@
 	if (m == NULL)
 		return NULL;
 	sysdict = PyModule_GetDict(m);
+#define SET_SYS_FROM_STRING(key, value)			\
+	v = value;					\
+	if (v != NULL)					\
+		PyDict_SetItemString(sysdict, key, v);	\
+	Py_XDECREF(v)
 
 	{
 		/* XXX: does this work on Win/Win64? (see posix_fstat) */
@@ -1165,19 +1168,16 @@
                              PyDict_GetItemString(sysdict, "displayhook"));
 	PyDict_SetItemString(sysdict, "__excepthook__",
                              PyDict_GetItemString(sysdict, "excepthook"));
-	PyDict_SetItemString(sysdict, "version",
-			     v = PyUnicode_FromString(Py_GetVersion()));
-	Py_XDECREF(v);
-	PyDict_SetItemString(sysdict, "hexversion",
-			     v = PyLong_FromLong(PY_VERSION_HEX));
-	Py_XDECREF(v);
+	SET_SYS_FROM_STRING("version",
+			     PyUnicode_FromString(Py_GetVersion()));
+	SET_SYS_FROM_STRING("hexversion",
+			     PyLong_FromLong(PY_VERSION_HEX));
 	svnversion_init();
-	v = Py_BuildValue("(UUU)", "CPython", branch, svn_revision);
-	PyDict_SetItemString(sysdict, "subversion", v);
-	Py_XDECREF(v);
-	PyDict_SetItemString(sysdict, "dont_write_bytecode",
-			     v = PyBool_FromLong(Py_DontWriteBytecodeFlag));
-	Py_XDECREF(v);
+	SET_SYS_FROM_STRING("subversion",
+			    Py_BuildValue("(UUU)", "CPython", branch,
+					  svn_revision));
+	SET_SYS_FROM_STRING("dont_write_bytecode",
+			    PyBool_FromLong(Py_DontWriteBytecodeFlag));
 	/*
 	 * These release level checks are mutually exclusive and cover
 	 * the field, so don't get too fancy with the pre-processor!
@@ -1192,12 +1192,6 @@
 	s = "final";
 #endif
 
-#define SET_SYS_FROM_STRING(key, value)			\
-	v = value;					\
-	if (v != NULL)					\
-		PyDict_SetItemString(sysdict, key, v);	\
-	Py_XDECREF(v)
-
 	SET_SYS_FROM_STRING("version_info",
 			    Py_BuildValue("iiiUi", PY_MAJOR_VERSION,
 					       PY_MINOR_VERSION,
@@ -1244,7 +1238,6 @@
 	SET_SYS_FROM_STRING("winver",
 			    PyUnicode_FromString(PyWin_DLLVersionString));
 #endif
-#undef SET_SYS_FROM_STRING
 	if (warnoptions == NULL) {
 		warnoptions = PyList_New(0);
 	}
@@ -1255,12 +1248,14 @@
 		PyDict_SetItemString(sysdict, "warnoptions", warnoptions);
 	}
 
-	PyStructSequence_InitType(&FlagsType, &flags_desc);
-	PyDict_SetItemString(sysdict, "flags", make_flags());
+	if (FlagsType.tp_name == 0)
+		PyStructSequence_InitType(&FlagsType, &flags_desc);
+	SET_SYS_FROM_STRING("flags", make_flags());
 	/* prevent user from creating new instances */
 	FlagsType.tp_init = NULL;
 	FlagsType.tp_new = NULL;
 
+#undef SET_SYS_FROM_STRING
 	if (PyErr_Occurred())
 		return NULL;
 	return m;

Modified: python/branches/py3k/configure
==============================================================================
--- python/branches/py3k/configure	(original)
+++ python/branches/py3k/configure	Thu Jan 31 15:31:45 2008
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in Revision: 59829 .
+# From configure.in Revision: 60144 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.61 for python 3.0.
 #
@@ -14603,6 +14603,12 @@
 _ACEOF
 
 		       ;;
+      AIX/5)
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_BROKEN_POSIX_SEMAPHORES 1
+_ACEOF
+
+		       ;;
       esac
 
       { echo "$as_me:$LINENO: checking if PTHREAD_SCOPE_SYSTEM is supported" >&5

Modified: python/branches/py3k/configure.in
==============================================================================
--- python/branches/py3k/configure.in	(original)
+++ python/branches/py3k/configure.in	Thu Jan 31 15:31:45 2008
@@ -1965,6 +1965,9 @@
       SunOS/5.8) AC_DEFINE(HAVE_BROKEN_POSIX_SEMAPHORES, 1,
 		       Define if the Posix semaphores do not work on your system)
 		       ;;
+      AIX/5) AC_DEFINE(HAVE_BROKEN_POSIX_SEMAPHORES, 1,
+		       Define if the Posix semaphores do not work on your system)
+		       ;;
       esac
 
       AC_MSG_CHECKING(if PTHREAD_SCOPE_SYSTEM is supported)


More information about the Python-3000-checkins mailing list