On Thu, 7 Apr 2022 at 02:17, Christopher Barker <python...@gmail.com> wrote:
>
> On Wed, Apr 6, 2022 at 5:11 AM Oscar Benjamin <oscar.j.benja...@gmail.com> 
> wrote:
>> > I'd be curious to know what alternatives you see. When a user writes `x + 
>> > y` with both `x` and `y` instances of `decimal.Decimal`, the decimal 
>> > module needs to know what precision to compute the result to
>> (as well as what rounding mode to use, etc.). Absent a thread-local context 
>> or task-local context, where would that precision information come from?
>
> Why is that absent? -- it seems a task local and/or thread local context is 
> exactly what should be done.

https://docs.python.org/3/library/decimal.html#decimal.localcontext

The Decimal module has a global default context, and per-thread
contexts which can be set permanently or with a context manager.

It never offers per-module or per-function or any other scope of
configuration; at any given moment, there is precisely one context for
code running in any particular thread.

>> One possibility is to attach the context information to the instances
>> so it's like:
>
> That seems the obvious thing to me -- a lot more like we already have with 
> mixing integers and floats, and/or mixing different precision floats in other 
> languages (and numpy).

Not so obvious to me, as it would require inordinate amounts of
fiddling around when you want to dynamically adjust your precision.
You'd have to reassign every Decimal instance to have the new
settings.

Also: what happens when there's a conflict? Which one wins? Let's say
you do "a + b" where the two were created with different contexts - do
you use the lower precision? the higher precision? What about rounding
settings?

Do you need a meta-config that explains how to resolve conflicts
between configs? Where would that be stored?

Maybe the current way seems more obvious to me since I come from a
background of working in REXX, which also had global configuration of
these sorts of things (eg "NUMERIC DIGITS 1234" to set the precision,
"NUMERIC FUZZ 2" to make numbers compare equal if close). It just
seems like the simplest and most convenient way to do things.

> Perhaps even something as simple as "Preserve the precision of the highest 
> precision operand" would go a long way.

And some people will loudly dispute that, wanting to avoid false
precision. "Adopt the precision of the lowest precision operand" is,
for many purposes, much more sane. You'll never satisfy everyone.

>> Realistically do many users want to use many different contexts and
>> regularly switch between them? I expect the common use case is wanting
>> to do everything in a particular context that just isn't the default
>> one.
>
>
> I don't know that that's true in the least -- sure, for a basic script, 
> absolutely, but PYthon has become a large ecosystem of third party packages 
> -- people make a LOT of large systems involving many complex third party 
> packages -- the builder of the system may not even know a package is using 
> Decimals -- let alone two different third party packages using them in very 
> different ways -- it's literally impossible for the developer of package A to 
> know how package B works or that someone might be using both.
>

Indeed. But I don't hear people complaining that they need to have
per-module Decimal contexts, possibly since it's never actually a
module-by-module consideration.

The one thing that threaded contexts don't handle is asyncio, and I
haven't checked this, but I believe that "with Decimal.localcontext()
as ctx:" uses an asyncio-aware definition of "thread-local" that
actually allows multiple tasks to have independent contexts. That
would mean that this sort of thing will work sanely:

async def task1():
    with Decimal.localcontext() as ctx:
        ctx.prec = 100
        await something()
        a = b + c

async def task2():
    with Decimal.localcontext() as ctx:
        ctx.prec = 4
        await somethingelse()
        a = b + c

and regardless of exactly what each task does, there's a guarantee
that code executed inside the 'with' blocks has the appropriate
context. And that's true even if parts of it are imported from other
modules.

I've never used asyncio + Decimal.localcontext, so I can't say further on that.

> Then put all this behind a multithreading web server, and you have a recipe 
> for chaos.
>

That's handled, since Decimal contexts are set on a per-thread basis.

ChrisA
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/UI5ZN7ED4JZKXUDDTLAPOEXU5YZXZ7WA/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to