[Python-Dev] Store timestamps as decimal.Decimal objects

Nick Coghlan ncoghlan at gmail.com
Wed Feb 1 05:08:34 CET 2012


On Wed, Feb 1, 2012 at 12:35 PM, Antoine Pitrou <solipsis at pitrou.net> wrote:
> It strikes me as inelegant to have to do so much typing for something
> as simple as getting the current time. We should approach the
> simplicity of ``time.time(format='decimal')`` or
> ``time.decimal_time()``.

Getting the current time is simple (you can already do it), getting
access to high precision time without performance regressions or
backwards incompatiblities or excessive code duplication is hard.

There's a very simple rule in large scale software development:
coupling is bad and you should do everything you can to minimise it.
Victor's approach throws that out the window by requiring that time
and os know about every possible output format for time values.

That's why protocols are so valuable: instead of having MxN points of
interconnection, you just define a standard protocol as the basis for
interaction, and the consumer of the protocol doesn't need to care
about the details of the provider, they just care about the protocol
itself.

So, the question becomes how to solve the problem of exposing high
resolution timestamps to Python code in a way that:
- is applicable not just to time.time(), but also to os.stat(),
time.clock(), time.wall_clock() and any other timestamp sources I've
forgotten.
- is backwards compatible for all those use cases
- doesn't cause a significant performance regression for any of those use cases
- doesn't cause excessive coupling between the time and os modules and
other parts of Python
- doesn't excessively duplicate code
- doesn't add too much machinery for a relatively minor problem

The one key aspect that I think Victor's suggestion gets right is that
we want a way to request high precision time from the *existing* APIs,
and that this needs to be selected on a per call basis rather than
globally for the whole application.

The big advantage of going with a callback based approach is that it
gives you flexibility and low coupling without any additional
supporting infrastructure, and you have the full suite of Python tools
available to deal with any resulting verbosity issues.

For example, it would become *trivial* to write Alexander's suggested
"hirestime" module that always returned decimal.Decimal objects:

    _hires = decimal.Decimal.from_components

    def time():
        return time.time(convert=_hires)

    def clock():
        return time.clock(convert=_hires)

    def stat(path):
        return os.stat(path, timestamps=_hires)

    # etc...

PJE is quite right that using a new named protocol rather than a
callback with a particular signature could also work, but I don't see
a lot of advantages in doing so.

On the other hand, if you go with the "named output format",
"hires=True" or new API approaches, you end up having to decide what
additional coupling you're going to introduce to time and os. Now, in
this case, I actually think there *is* a reasonable option available
if we decide to go down that path:
- incorporate Stefan Krah's cdecimal work into the standard library
- add a "hires=False" flag to affected APIs
- return a Decimal instance with full available precision if
"hires=True" is passed in.
- make time and os explicitly depend on the ability to create
decimal.Decimal instances

A hirestime module is even easier to implement in that case:

    def time():
        return time.time(hires=True)

    def clock():
        return time.clock(hires=True)

    def stat(path):
        return os.stat(path, hires=True)

    # etc...

All of the other APIs (datetime, timedelta, etc) can then just be
updated to also accept a Decimal object as input, rather than handling
the (integer, fraction, exponent) callback signature I suggested.

Either extreme (full flexibility via a callback API or protocol, or
else settling specifically on decimal.Decimal and explicitly making
time and os dependent on that type) makes sense to me. A wishy-washy
middle ground that introduces a dependency from time and os onto
multiple other modules *without* making the API user extensible
doesn't seem reasonable at all.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-Dev mailing list