I’m learning OOP by trying to build a rudimentary banking ATM machine. It started out an an exercise for Fred Baptiste’s Udemy online courseware but I am now extending and building on top of the feature set just for fun.
Now I am endeavoring to add these features:
- Using Decimals instead of Floats
- “Bankers Rounding” (“half-way” amounts should be rounded up) to 2 significant digits for all transactions
This is what I am trying to accomplish today. This might sound weird but based on my testing, I’m not sure if I have succeeded. That’s why I need your help, Pythonistas!
The tutorial I am working with is titled “Python Decimal”. The tutorial demonstrates how to use decimals and rounding. Here is some sample coding running in my trusty Python REPL:
$ 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.rounding = decimal.ROUND_HALF_UP
>>> x = Decimal('2.3456')
>>> x
Decimal('2.3456')
>>> round(x,2)
Decimal('2.35')
>>>
So that works. Here is my script (reduced test case):
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}'
Take note that in my script above I do not get a context or set the rounding
to ROUND_HALF_UP
. Here is me importing the script in my REPL and instantiating:
>>> import script
>>> BA = script.Account('Winston','Smith')
>>> BA.balance
Decimal('0.00')
>>> BA.deposit(0.505)
'D-547'
>>> BA.balance
Decimal('0.51')
>>>
Here my script is rounding half up even without specifying .getcontext()
. So my script is rounding up when I am expecting it to round down (Python’s default).
Here are my questions for all of you:
First of all, why is my script working when it shouldn’t be?
Secondly, for these two lines:
ctx = decimal.getcontext()
ctx.rounding = decimal.ROUND_HALF_UP
- …the
ctx
variable is an instantiation of the.getcontext()
function or class method located somewhere inside thedecimal
package as described in the official docs. Where in this understanding am I correct or incorrect? - In the next line,
ctx.rounding
is declared based on thedecimal
package’s setting toROUND_HALF_UP
(among a few the other options as covered in the official Python docs). Is this correct? [/list]
My third (and perhaps my most important) question is: How and why does the above ctx
instantiation have any bearing on the subsequent lines in the REPL (if any)?:
>>> x = Decimal('2.3456')
>>> x
Decimal('2.3456')
>>> round(x,2)
Decimal('2.35')
>>>
My final question is, where in my OOP script should I place / invoke the .getcontext()
method from the decimal
package? Inside the scope of the Account
class or outside? Or would it be better suited beneath a dunder main declaration at the bottom of the script?
I guess overall here I am just struggling to grasp how, when, or where .getcontext()
is used or if it is even necessary at all. Could you Pythonistas kindly clarify?