May-04-2022, 06:15 AM
Hi @bowlofred, Thank you for your reply. I’ve done some more experimentation in my REPL based on your feedback. I tried the context manager and it turns out to behave as you predicted. It rounds up or down. Here it is:
@deanhystad, Thank you for sharing the two specific quotes on
I personally find the Python docs to be written by programmers, for programmers, meaning they aren’t very helpful to novices like me. I prefer reading guides like on Geek for Geeks, Programiz, PythonTutorial.net, YouTube, and Python forums in general because in all of these locations on the web, I can find helpful guides and experienced programers who share specific practical examples written in language that is candid, approachable, and friendly rather the robotic and rigid
I think I am beginning to understand, although I still have a few points of clarification related to these two particular passages.
When
So in a sense, by analogy, does
So to compare, when a
For the purposes of my script in my original post (but also copied below), I’d like all my Decimals to ROUND_HALF_UP. So where in my script should I add it? Within the scope of the
Here is my original script:
$ bpython bpython version 0.22.1 on top of Python 3.10.4 /usr/bin/python >>> import decimal >>> from decimal import Decimal >>> ctx = decimal.getcontext() >>> x = Decimal('2.35') >>> y = Decimal('3.35') >>> with decimal.localcontext() as ctx: ... ctx.rounding = decimal.ROUND_HALF_UP ... print(round(x,1)) ... print(round(y,1)) ... 2.4 3.4 >>> with decimal.localcontext() as ctx: ... ctx.rounding = decimal.ROUND_DOWN ... print(round(x,1)) ... print(round(y,1)) ... 2.3 3.3But when we return to calling
.getcontext
that we were originally working with, it shows the change but Python is still rounding UP
even after I tell Python to round DOWN
. See here:$ bpython bpython version 0.22.1 on top of Python 3.10.4 /usr/bin/python >>> import decimal >>> from decimal import Decimal >>> ctx = decimal.getcontext() >>> ctx Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1 , clamp=0, flags=[], traps=[DivisionByZero, Overflow, InvalidOperation]) >>> ctx.rounding = decimal.ROUND_DOWN >>> ctx Context(prec=28, rounding=ROUND_DOWN, Emin=-999999, Emax=999999, capitals=1, cla mp=0, flags=[], traps=[DivisionByZero, Overflow, InvalidOperation]) >>> x = Decimal('2.35') >>> y = Decimal('3.35') >>> print(round(x,1)) 2.4 >>> ctx Context(prec=28, rounding=ROUND_DOWN, Emin=-999999, Emax=999999, capitals=1, cla mp=0, flags=[], traps=[DivisionByZero, Overflow, InvalidOperation]) >>> print(round(y,1)) 3.4 >>> y Decimal('3.35') >>>So I whipped out the official python REPL and entered the same commands:
$ python Python 3.10.4 (main, Mar 23 2022, 23:05:40) [GCC 11.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import decimal >>> from decimal import Decimal >>> ctx = decimal.getcontext() >>> ctx Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[DivisionByZero, Overflow, InvalidOperation]) >>> ctx.rounding = decimal.ROUND_DOWN >>> ctx Context(prec=28, rounding=ROUND_DOWN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[DivisionByZero, Overflow, InvalidOperation]) >>> x = Decimal('2.35') >>> y = Decimal('3.35') >>> print(round(x,1)) 2.3 >>> ctx Context(prec=28, rounding=ROUND_DOWN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[DivisionByZero, Overflow, InvalidOperation]) >>> print(round(y,1)) 3.3 >>> y Decimal('3.35') >>> ctx.rounding = decimal.ROUND_UP >>> ctx Context(prec=28, rounding=ROUND_UP, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[DivisionByZero, Overflow, InvalidOperation]) >>> print(round(x,1)) 2.4 >>> print(round(y,1)) 3.4 >>>It’s working now. This proves @deanhystad’s suspicion that the problem is with the
bpython
REPL I am using. There seems to be a related known outstanding issue on the bpython
project's GitHub repo with the decimal module. Lesson learned: Don’t trust bpython
. @deanhystad, Thank you for sharing the two specific quotes on
docs.python.org
. The official Python docs are vast and verbose. Even if I spent all weekend long reading the entire doc entry on the decimal
package, it still probably wouldn’t have registered in my mind. So I appreciate you highlighting the specific passage relevant to my issue.I personally find the Python docs to be written by programmers, for programmers, meaning they aren’t very helpful to novices like me. I prefer reading guides like on Geek for Geeks, Programiz, PythonTutorial.net, YouTube, and Python forums in general because in all of these locations on the web, I can find helpful guides and experienced programers who share specific practical examples written in language that is candid, approachable, and friendly rather the robotic and rigid
docs.python.org
.(Apr-29-2022, 02:40 PM)deanhystad Wrote:
Output:The context for arithmetic is an environment specifying precision, rounding rules, limits on exponents, flags indicating the results of operations, and trap enablers which determine whether signals are treated as exceptions. Rounding options include ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP, and ROUND_05UP.
Output:The usual start to using decimals is importing the module, viewing the current context with getcontext() and, if necessary, setting new values for precision, rounding, or enabled traps:
I think I am beginning to understand, although I still have a few points of clarification related to these two particular passages.
When
getcontext()
is called and the rounding=”ROUND_UP”
argument is passed in, does this establish the behavior for all rounding operations for the entire script for as long as the script is running?So in a sense, by analogy, does
.getcontext
work like an ‘environmental variable’? I have a little bit of experience with environmental variables in some Django projects I have been playing with on and off recently. With Django, the DEBUG
setting applies to all web apps. In my local testing environment, DEBUG
is set to True
which helps the developer diagnose and identify bugs. But for production, DEBUG
is set to False
, preventing the exposure of sensitive information to public web site visitors. So to compare, when a
.getcontext
argument is passed in such as ROUND_DOWN
, does the ROUND_DOWN
behavior then apply to the whole script at runtime when it is called, causing all round()
methods to behave the same way?For the purposes of my script in my original post (but also copied below), I’d like all my Decimals to ROUND_HALF_UP. So where in my script should I add it? Within the scope of the
Account
class? Embedded beneath the dunder __init__
method? Or outside all classes near the top when all the packages are imported and initialized?Here is my original script:
import decimal from decimal import Decimal from random import randint class Account: def __init__(self, first_name, last_name,starting_balance=0.00): self.first_name = first_name self.last_name = last_name self.balance = round(Decimal(starting_balance),2) self.transaction_id = randint(101,999) def deposit(self, amount): self.balance += round(Decimal(amount),2) self.transaction_id += randint(101,999) - randint(101,999) return f'D-{self.transaction_id}' def withdraw(self, amount): self.balance -= round(Decimal(amount),2) self.transaction_id += randint(101,999) - randint(101,999) return f'W-{self.transaction_id}'So where should the following context declaration be placed in the above script?
ctx = decimal.getcontext() ctx.rounding = decimal.ROUND_HALF_UP