def _sum (data, start=None): if start is not None: t = set((type(start),)) n, d = _exact_ratio(start) else: t = set() n = 0 d = 1 partials = {d: n} # map {denominator: sum of numerators} # Micro-optimizations. exact_ratio = _exact_ratio partials_get = partials.get # Add numerators for each denominator, and build up a set of all types. for x in data: t.add(type(x)) n, d = exact_ratio(x) partials[d] = partials_get(d, 0) + n T = _coerce_types(t) # decide which type to use based on set of all types if None in partials: assert issubclass(T, (float, Decimal)) assert not math.isfinite(partials[None]) return T(partials[None]) total = Fraction() for d, n in sorted(partials.items()): total += Fraction(n, d) if issubclass(T, int): assert total.denominator == 1 return T(total.numerator) if issubclass(T, Decimal): return T(total.numerator)/total.denominator return T(total) def _coerce_types (types): if len(types) == 1: return next(iter(types)) if all(issubclass(t, numbers.Integral) for t in types): return int if all(issubclass(t, numbers.Rational) for t in types): return Fraction if any(issubclass(t, Decimal) for t in types): if all(issubclass(t, (numbers.Integral, Decimal)) for t in types): return Decimal raise TypeError('cannot coerce type Decimal and non-Integral type(s)') return float def _coerce_types_2 (types): if len(types) == 1: return next(iter(types)) if all(issubclass(t, numbers.Integral) for t in types): return int if all(issubclass(t, numbers.Rational) for t in types): return Fraction if any(issubclass(t, Decimal) for t in types): if all(issubclass(t, (numbers.Integral, Decimal)) for t in types): return Decimal if not all(issubclass(t, (numbers.Integral, Decimal, float)) for t in types): raise TypeError('cannot coerce type Decimal and non-Integral type(s) {0}' .format(', '.join(str(t) for t in types if not issubclass(t, (numbers.Integral, Decimal, float))))) return float