6
\$\begingroup\$

I am setting up a kids bank account class to teach them how to save, and myself how to write a class in Python. The original idea was to create a pandas DataFrame that will show how the money gains interest by loading:

<AccountName>.df 

First I created the DataFrame of 365 days with datetime.date.today() + datetime.timedelta(days=236) as the indices which I guess made the looking up of index for the daily interest increment a bit cumbersome... to say the least.

class  Account:


    def __init__(self, holder, start_date):
        import datetime 
        import pandas as pd

        self.df = pd.DataFrame(index=pd.date_range(start_date, start_date + datetime.timedelta(365), freq='D'), columns=['deposit', 'withdrawl', 'balance'])
        self.df.withdrawl = 0.0
        self.df.deposit = 0.0
        self.df.balance = 0.0
        self.df.dif = 0.0

        for i in self.df.index[1:]:
            self.df.loc[i,('balance')] = self.df.loc[str(datetime.datetime.strptime(str(i)[:10], '%Y-%m-%d') - datetime.timedelta(days=1))[:10], ('balance')] * (1+(0.08 / 365))

        self.history = []

        self.holder = holder

    def __str__(self):
        return 'The account of: {0}, balance is: {1} '.format(self.holder, self.df.loc[str(datetime.datetime.today())[:10], 'balance'])

    def __repr__(self):
        return '{0.__class__.__name__}(name={0.holder})(balance={1})'.format(self, self.df.loc[str(datetime.datetime.today())[:10], 'balance'])

    def get_balance(self):
        return self.df.loc[str(datetime.datetime.today())[:10], 'balance']

    def make_deposit(self, amount, date):
        self.history.append((amount, date))
        if type(date) is datetime.datetime or datetime.date:
            self.df.loc[date.strftime('%Y-%m-%d'), ('deposit')] += amount
            self.df.loc[date.strftime('%Y-%m-%d'), ('balance')] += amount
        for i in self.df.index[self.df.index.slice_locs(date + datetime.timedelta(days=1))[0] :]:
            self.df.loc[i, 'balance'] = self.df.loc[i-datetime.timedelta(days=1), 'balance']* (1+(0.08 / 365)) + self.df.loc[i, 'deposit'] - self.df.loc[i, 'withdrawl']

    def withdraw_money(self, amount, date):
        self.history.append((amount*-1, date))
        if type(date) is datetime.datetime or datetime.date:
            self.df.loc[date.strftime('%Y-%m-%d'), ('withdrawl')] += amount
            self.df.loc[date.strftime('%Y-%m-%d'), ('balance')] -= amount
        for i in self.df.index[self.df.index.slice_locs(date + datetime.timedelta(days=1))[0] :]:
            self.df.loc[i, 'balance'] = self.df.loc[i-datetime.timedelta(days=1), 'balance']* (1+(0.08 / 365)) + self.df.loc[i, 'deposit'] - self.df.loc[i, 'withdrawl']

I am looking for improvement ideas for that (also repeating in all the functions). I am also looking for a neater way, within pandas of assigning yesterday's balance + todays deposit - today's withdraw + the daily interest rate. (I know it's an extremely generous interest, but they are my kids after all and with the little pennies they manage to collect it doesn't amount to much...)

I start an account like so:

import datetime
test = Account('my_name', datetime.date.today())

I've improved my __str__ and __repr__ methods after I read all the suggestions suggested on this question, didn't do anything about privacy and properties but first thing first.

Wouldn't changing the date from the index to its own column and using integer indices make it easier to access and lookup data?

\$\endgroup\$
1
\$\begingroup\$

I think your design is a bit "overkill". After all, banks don't keep empty records for each day of the year, waiting for you to come along and perform a transaction.
Rather than using a DataFrame, I think you'd be better off separating the data record into a class of its own, with the increment and decrement functions.

The display functionality is not part of the data record, it would be a separate class itself, and inheritable by ATMs or a Teller/Bank Manager/technician's computer. Regardless, this is something for kids, so it's fine to violate some SOLID principals.

Regarding def __init__(self, holder, start_date): you could probably make start_date = date.today() as transactions tend to happen on the same day, unless you're performing some cheque activity (which is delayed).

As to your question, if you change the date from the index into its own column, you're shifting the column[:loc] as the lookup, essentially adding an extra step.
For using integer indices to lookup data, it's a bad idea as you should try to keep any [lookup_integer] values as defined constants - so they're not arbitrary numbers (you'd be surprised how often people make simple input mistakes when coding, and as they're usually valid integers, people are scratching their heads why a date is in the address of a decimal number (addition and subtraction would then still be valid operations, so it's not picked up immediately unless you're performing tests on data as part of your CI process, and you go live with faulty code).

Good luck!

\$\endgroup\$
  • \$\begingroup\$ thanks very much, @C. Harley . I appreciate your useful advice and I will give it a go. \$\endgroup\$ – manandearth Mar 12 '18 at 6:37
  • \$\begingroup\$ another reason I used the data frame to keep the data with an actual date object instead of date.today was because I was going to just save each account instance as a Jupyter notebook session ( this might also you might call an over kill) In this method you can run afresh the whole history of payments as code and therefore need proper time definitions and not date.today, that will change with the date of execution.. Do you suggest to just keep a list or a list of lists instaed? what will be the best method of keeping the records? \$\endgroup\$ – manandearth Mar 14 '18 at 16:17
  • \$\begingroup\$ So you'll actually be keeping (if I understand where you're going) a list of Accounts. Looking at the most recent code at the top, you have class Account which will maintain the info per account, correct? so [Account(), Account(), ...] \$\endgroup\$ – C. Harley Mar 15 '18 at 4:56
  • \$\begingroup\$ As for the best method of keeping the records, probably you could keep the construction inside a cell in a notebook? However, if you're planning on maintaining daily changes, are you thinking of saving to disk? Perhaps use pickle to convert the data to/from a file.docs.python.org has information on pickle (read carefully, you might also be pickling the functions with the data). \$\endgroup\$ – C. Harley Mar 15 '18 at 5:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.