[Python-Dev] PEP: New timestamp formats

Paul Moore p.f.moore at gmail.com
Thu Feb 2 11:53:49 CET 2012


On 2 February 2012 03:47, Nick Coghlan <ncoghlan at gmail.com> wrote:
> Rather than being timestamp specific, such a protocol would be a
> general numeric protocol. If (integer, numerator, denominator) is used
> (i.e. a "mixed number" in mathematical terms), then "__from_mixed__"
> would be an appropriate name. If (integer, fractional, exponent) is
> used (i.e. a fixed point notation), then "__from_fixed__" would work.
>
>    # Algorithm for a "from mixed numbers" protocol, assuming division
> doesn't lose precision...
>    def __from_mixed__(cls, integer, numerator, denominator):
>        return cls(integer) + cls(numerator) / cls(denominator)
>
>    # Algorithm for a "from fixed point" protocol, assuming negative
> exponents don't lose precision...
>    def __from_fixed__(cls, integer, mantissa, base, exponent):
>        return cls(integer) + cls(mantissa) * cls(base) ** cls(exponent)
>
> >From a *usage* point of view, this idea is actually the same as the
> proposal currently in the PEP. The difference is that instead of
> adding custom support for a few particular types directly to time and
> os, it instead defines a more general purpose protocol that covers not
> only this use case, but also any other situation where high precision
> fractions are relevant.
>
> One interesting question with a named protocol approach is whether
> such a protocol should *require* explicit support, or if it should
> fall back to the underlying mathematical operations. Since the
> conversions to float and int in the timestamp case are already known
> to be lossy, permitting lossy conversion via the mathematical
> equivalents seems reasonable, suggesting possible protocol definitions
> as follows:
>
>    # Algorithm for a potentially precision-losing "from mixed numbers" protocol
>    def from_mixed(cls, integer, numerator, denominator):
>        try:
>            factory = cls.__from_mixed__
>        except AttributeError:
>            return cls(integer) + cls(numerator) / cls(denominator)
>        return factory(integer, numerator, denominator)
>
>    # Algorithm for a potentially lossy "from fixed point" protocol
>    def from_fixed(cls, integer, mantissa, base, exponent):
>        try:
>            factory = cls.__from_fixed__
>        except AttributeError:
>            return cls(integer) + cls(mantissa) * cls(base) ** cls(exponent)
>        return factory(integer, mantissa, base, exponent)

The key problem with a protocol is that the implementer has to make
these decisions. The callback approach defers that decision to the end
user. After all, the end user is the one who knows for his app whether
precision loss is acceptable.

You could probably also have a standard named protocol which can be
used as a callback in straightforward cases

    time.time(callback=timedelta.__from_mixed__)

That's wordy, and a bit ugly, though. The callback code could
special-case types and look for __from_mixed__, I guess. Or use an
ABC, and have the code that uses the callback do

    if issubclass(cb, MixedNumberABC):
        return cb.__from_mixed__(whole, num, den)
    else:
        return cb(whole, num, den)

(The second branch is the one that allows the user to override the
predefined types that work - if you omit that, you're back to a named
protocol and ABCs don't gain you much beyond documentation).

Part of me feels that there's a use case for generic functions in
here, but maybe not (as it's overloading on the return type). Let's
not open that discussion again, though.

Paul.


More information about the Python-Dev mailing list