Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7b3ce6a

Browse files
committed
Merged revisions 60441-60474 via svnmerge from
svn+ssh://[email protected]/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). ........
1 parent 4b8db41 commit 7b3ce6a

11 files changed

Lines changed: 275 additions & 60 deletions

File tree

Doc/library/itertools.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,5 +511,16 @@ which incur interpreter overhead. ::
511511
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
512512
return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)
513513

514-
514+
def roundrobin(*iterables):
515+
"roundrobin('abc', 'd', 'ef') --> 'a', 'd', 'e', 'b', 'f', 'c'"
516+
# Recipe contributed by George Sakkis
517+
pending = len(iterables)
518+
nexts = cycle(iter(it).next for it in iterables)
519+
while pending:
520+
try:
521+
for next in nexts:
522+
yield next()
523+
except StopIteration:
524+
pending -= 1
525+
nexts = cycle(islice(nexts, pending))
515526

Doc/library/numbers.rst

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,144 @@ The numeric tower
9797
3-argument form of :func:`pow`, and the bit-string operations: ``<<``,
9898
``>>``, ``&``, ``^``, ``|``, ``~``. Provides defaults for :func:`float`,
9999
:attr:`Rational.numerator`, and :attr:`Rational.denominator`.
100+
101+
102+
Notes for type implementors
103+
---------------------------
104+
105+
Implementors should be careful to make equal numbers equal and hash
106+
them to the same values. This may be subtle if there are two different
107+
extensions of the real numbers. For example, :class:`rational.Rational`
108+
implements :func:`hash` as follows::
109+
110+
def __hash__(self):
111+
if self.denominator == 1:
112+
# Get integers right.
113+
return hash(self.numerator)
114+
# Expensive check, but definitely correct.
115+
if self == float(self):
116+
return hash(float(self))
117+
else:
118+
# Use tuple's hash to avoid a high collision rate on
119+
# simple fractions.
120+
return hash((self.numerator, self.denominator))
121+
122+
123+
Adding More Numeric ABCs
124+
~~~~~~~~~~~~~~~~~~~~~~~~
125+
126+
There are, of course, more possible ABCs for numbers, and this would
127+
be a poor hierarchy if it precluded the possibility of adding
128+
those. You can add ``MyFoo`` between :class:`Complex` and
129+
:class:`Real` with::
130+
131+
class MyFoo(Complex): ...
132+
MyFoo.register(Real)
133+
134+
135+
Implementing the arithmetic operations
136+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
137+
138+
We want to implement the arithmetic operations so that mixed-mode
139+
operations either call an implementation whose author knew about the
140+
types of both arguments, or convert both to the nearest built in type
141+
and do the operation there. For subtypes of :class:`Integral`, this
142+
means that :meth:`__add__` and :meth:`__radd__` should be defined as::
143+
144+
class MyIntegral(Integral):
145+
146+
def __add__(self, other):
147+
if isinstance(other, MyIntegral):
148+
return do_my_adding_stuff(self, other)
149+
elif isinstance(other, OtherTypeIKnowAbout):
150+
return do_my_other_adding_stuff(self, other)
151+
else:
152+
return NotImplemented
153+
154+
def __radd__(self, other):
155+
if isinstance(other, MyIntegral):
156+
return do_my_adding_stuff(other, self)
157+
elif isinstance(other, OtherTypeIKnowAbout):
158+
return do_my_other_adding_stuff(other, self)
159+
elif isinstance(other, Integral):
160+
return int(other) + int(self)
161+
elif isinstance(other, Real):
162+
return float(other) + float(self)
163+
elif isinstance(other, Complex):
164+
return complex(other) + complex(self)
165+
else:
166+
return NotImplemented
167+
168+
169+
There are 5 different cases for a mixed-type operation on subclasses
170+
of :class:`Complex`. I'll refer to all of the above code that doesn't
171+
refer to ``MyIntegral`` and ``OtherTypeIKnowAbout`` as
172+
"boilerplate". ``a`` will be an instance of ``A``, which is a subtype
173+
of :class:`Complex` (``a : A <: Complex``), and ``b : B <:
174+
Complex``. I'll consider ``a + b``:
175+
176+
1. If ``A`` defines an :meth:`__add__` which accepts ``b``, all is
177+
well.
178+
2. If ``A`` falls back to the boilerplate code, and it were to
179+
return a value from :meth:`__add__`, we'd miss the possibility
180+
that ``B`` defines a more intelligent :meth:`__radd__`, so the
181+
boilerplate should return :const:`NotImplemented` from
182+
:meth:`__add__`. (Or ``A`` may not implement :meth:`__add__` at
183+
all.)
184+
3. Then ``B``'s :meth:`__radd__` gets a chance. If it accepts
185+
``a``, all is well.
186+
4. If it falls back to the boilerplate, there are no more possible
187+
methods to try, so this is where the default implementation
188+
should live.
189+
5. If ``B <: A``, Python tries ``B.__radd__`` before
190+
``A.__add__``. This is ok, because it was implemented with
191+
knowledge of ``A``, so it can handle those instances before
192+
delegating to :class:`Complex`.
193+
194+
If ``A<:Complex`` and ``B<:Real`` without sharing any other knowledge,
195+
then the appropriate shared operation is the one involving the built
196+
in :class:`complex`, and both :meth:`__radd__` s land there, so ``a+b
197+
== b+a``.
198+
199+
Because most of the operations on any given type will be very similar,
200+
it can be useful to define a helper function which generates the
201+
forward and reverse instances of any given operator. For example,
202+
:class:`rational.Rational` uses::
203+
204+
def _operator_fallbacks(monomorphic_operator, fallback_operator):
205+
def forward(a, b):
206+
if isinstance(b, (int, long, Rational)):
207+
return monomorphic_operator(a, b)
208+
elif isinstance(b, float):
209+
return fallback_operator(float(a), b)
210+
elif isinstance(b, complex):
211+
return fallback_operator(complex(a), b)
212+
else:
213+
return NotImplemented
214+
forward.__name__ = '__' + fallback_operator.__name__ + '__'
215+
forward.__doc__ = monomorphic_operator.__doc__
216+
217+
def reverse(b, a):
218+
if isinstance(a, RationalAbc):
219+
# Includes ints.
220+
return monomorphic_operator(a, b)
221+
elif isinstance(a, numbers.Real):
222+
return fallback_operator(float(a), float(b))
223+
elif isinstance(a, numbers.Complex):
224+
return fallback_operator(complex(a), complex(b))
225+
else:
226+
return NotImplemented
227+
reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
228+
reverse.__doc__ = monomorphic_operator.__doc__
229+
230+
return forward, reverse
231+
232+
def _add(a, b):
233+
"""a + b"""
234+
return Rational(a.numerator * b.denominator +
235+
b.numerator * a.denominator,
236+
a.denominator * b.denominator)
237+
238+
__add__, __radd__ = _operator_fallbacks(_add, operator.add)
239+
240+
# ...

Lib/_abcoll.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -300,16 +300,6 @@ def pop(self):
300300
self.discard(value)
301301
return value
302302

303-
def toggle(self, value):
304-
"""Return True if it was added, False if deleted."""
305-
# XXX This implementation is not thread-safe
306-
if value in self:
307-
self.discard(value)
308-
return False
309-
else:
310-
self.add(value)
311-
return True
312-
313303
def clear(self):
314304
"""This is slow (creates N new iterators!) but effective."""
315305
try:
@@ -330,9 +320,13 @@ def __iand__(self, c: Container):
330320
return self
331321

332322
def __ixor__(self, it: Iterable):
333-
# This calls toggle(), so if that is overridded, we call the override
323+
if not isinstance(it, Set):
324+
it = self._from_iterable(it)
334325
for value in it:
335-
self.toggle(it)
326+
if value in self:
327+
self.discard(value)
328+
else:
329+
self.add(value)
336330
return self
337331

338332
def __isub__(self, it: Iterable):

Lib/numbers.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,13 @@ def denominator(self):
291291

292292
# Concrete implementation of Real's conversion to float.
293293
def __float__(self):
294-
"""float(self) = self.numerator / self.denominator"""
294+
"""float(self) = self.numerator / self.denominator
295+
296+
It's important that this conversion use the integer's "true"
297+
division rather than casting one side to float before dividing
298+
so that ratios of huge integers convert without overflowing.
299+
300+
"""
295301
return self.numerator / self.denominator
296302

297303

Lib/rational.py

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -178,27 +178,89 @@ def __str__(self):
178178
else:
179179
return '%s/%s' % (self.numerator, self.denominator)
180180

181-
""" XXX This section needs a lot more commentary
182-
183-
* Explain the typical sequence of checks, calls, and fallbacks.
184-
* Explain the subtle reasons why this logic was needed.
185-
* It is not clear how common cases are handled (for example, how
186-
does the ratio of two huge integers get converted to a float
187-
without overflowing the long-->float conversion.
188-
189-
"""
190-
191181
def _operator_fallbacks(monomorphic_operator, fallback_operator):
192182
"""Generates forward and reverse operators given a purely-rational
193183
operator and a function from the operator module.
194184
195185
Use this like:
196186
__op__, __rop__ = _operator_fallbacks(just_rational_op, operator.op)
197187
188+
In general, we want to implement the arithmetic operations so
189+
that mixed-mode operations either call an implementation whose
190+
author knew about the types of both arguments, or convert both
191+
to the nearest built in type and do the operation there. In
192+
Rational, that means that we define __add__ and __radd__ as:
193+
194+
def __add__(self, other):
195+
if isinstance(other, (int, Rational)):
196+
# Do the real operation.
197+
return Rational(self.numerator * other.denominator +
198+
other.numerator * self.denominator,
199+
self.denominator * other.denominator)
200+
# float and complex don't follow this protocol, and
201+
# Rational knows about them, so special case them.
202+
elif isinstance(other, float):
203+
return float(self) + other
204+
elif isinstance(other, complex):
205+
return complex(self) + other
206+
else:
207+
# Let the other type take over.
208+
return NotImplemented
209+
210+
def __radd__(self, other):
211+
# radd handles more types than add because there's
212+
# nothing left to fall back to.
213+
if isinstance(other, RationalAbc):
214+
return Rational(self.numerator * other.denominator +
215+
other.numerator * self.denominator,
216+
self.denominator * other.denominator)
217+
elif isinstance(other, Real):
218+
return float(other) + float(self)
219+
elif isinstance(other, Complex):
220+
return complex(other) + complex(self)
221+
else:
222+
return NotImplemented
223+
224+
225+
There are 5 different cases for a mixed-type addition on
226+
Rational. I'll refer to all of the above code that doesn't
227+
refer to Rational, float, or complex as "boilerplate". 'r'
228+
will be an instance of Rational, which is a subtype of
229+
RationalAbc (r : Rational <: RationalAbc), and b : B <:
230+
Complex. The first three involve 'r + b':
231+
232+
1. If B <: Rational, int, float, or complex, we handle
233+
that specially, and all is well.
234+
2. If Rational falls back to the boilerplate code, and it
235+
were to return a value from __add__, we'd miss the
236+
possibility that B defines a more intelligent __radd__,
237+
so the boilerplate should return NotImplemented from
238+
__add__. In particular, we don't handle RationalAbc
239+
here, even though we could get an exact answer, in case
240+
the other type wants to do something special.
241+
3. If B <: Rational, Python tries B.__radd__ before
242+
Rational.__add__. This is ok, because it was
243+
implemented with knowledge of Rational, so it can
244+
handle those instances before delegating to Real or
245+
Complex.
246+
247+
The next two situations describe 'b + r'. We assume that b
248+
didn't know about Rational in its implementation, and that it
249+
uses similar boilerplate code:
250+
251+
4. If B <: RationalAbc, then __radd_ converts both to the
252+
builtin rational type (hey look, that's us) and
253+
proceeds.
254+
5. Otherwise, __radd__ tries to find the nearest common
255+
base ABC, and fall back to its builtin type. Since this
256+
class doesn't subclass a concrete type, there's no
257+
implementation to fall back to, so we need to try as
258+
hard as possible to return an actual value, or the user
259+
will get a TypeError.
260+
198261
"""
199262
def forward(a, b):
200-
if isinstance(b, RationalAbc):
201-
# Includes ints.
263+
if isinstance(b, (int, Rational)):
202264
return monomorphic_operator(a, b)
203265
elif isinstance(b, float):
204266
return fallback_operator(float(a), b)

Objects/floatobject.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,9 @@ static PyStructSequence_Desc floatinfo_desc = {
106106
PyObject *
107107
PyFloat_GetInfo(void)
108108
{
109-
static PyObject* floatinfo;
109+
PyObject* floatinfo;
110110
int pos = 0;
111111

112-
if (floatinfo != NULL) {
113-
Py_INCREF(floatinfo);
114-
return floatinfo;
115-
}
116-
PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc);
117-
118112
floatinfo = PyStructSequence_New(&FloatInfoType);
119113
if (floatinfo == NULL) {
120114
return NULL;
@@ -143,8 +137,6 @@ PyFloat_GetInfo(void)
143137
Py_CLEAR(floatinfo);
144138
return NULL;
145139
}
146-
147-
Py_INCREF(floatinfo);
148140
return floatinfo;
149141
}
150142

@@ -1601,6 +1593,9 @@ _PyFloat_Init(void)
16011593
/* Initialize floating point repr */
16021594
_PyFloat_DigitsInit();
16031595
#endif
1596+
/* Init float info */
1597+
if (FloatInfoType.tp_name == 0)
1598+
PyStructSequence_InitType(&FloatInfoType, &floatinfo_desc);
16041599
}
16051600

16061601
void

Python/import.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ static char* sys_deletes[] = {
371371
"path", "argv", "ps1", "ps2",
372372
"last_type", "last_value", "last_traceback",
373373
"path_hooks", "path_importer_cache", "meta_path",
374+
/* misc stuff */
375+
"flags", "float_info",
374376
NULL
375377
};
376378

Python/marshal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,7 @@ r_object(RFILE *p)
482482
{
483483
/* NULL is a valid return value, it does not necessarily means that
484484
an exception is set. */
485-
PyObject *v, *v2, *v3;
485+
PyObject *v, *v2;
486486
long i, n;
487487
int type = r_byte(p);
488488
PyObject *retval;

0 commit comments

Comments
 (0)