We are going to rewrite the bank account closure problem we had a few assignments ago, only this time developing a formal class for a Bank User and Bank Account to use in our closure (recall previously we just had a nonlocal variable amount that we changed).
First we are going to define two types of bank accounts, run the code below:
In [3]:
from enum import Enum
class AccountType(Enum):
SAVINGS = 1
CHECKING = 2
An Enum stands for an enumeration, it's a convenient way for you to define lists of things. Typing:
In [4]:
AccountType.SAVINGS
Out[4]:
returns a Python representation of an enumeration. You can compare these account types:
In [5]:
AccountType.SAVINGS == AccountType.SAVINGS
Out[5]:
In [4]:
AccountType.SAVINGS == AccountType.CHECKING
Out[4]:
To get a string representation of an Enum, you can use:
In [6]:
AccountType.SAVINGS.name
Out[6]:
Constructor is BankAccount(self, owner, accountType) where owner is a string representing the name of the account owner and accountType is one of the AccountType enums
Methods withdraw(self, amount) and deposit(self, amount) to modify the account balance of the account
Override methods __str__ to write an informative string of the account owner and the type of account, and __len__ to return the balance of the account
In [6]:
class BankAccount:
def __init__(self, owner, accountType):
self.owner = owner
self.accountType = accountType
self.balance = 0
def withdraw(self, amount):
if self.balance >= amount and amount >= 0:
self.balance -= amount
return True
else:
return False
def deposit(self, amount):
if amount >= 0:
self.balance += amount
return True
else:
return False
def __str__(self):
return self.owner + "'s " + self.accountType.name + " Account"
def __len__(self):
return self.balance
Write some simple tests to make sure the BankAccount is working as expected.
Constructor BankUser(self, owner) where owner is the name of the account.
Method addAccount(self, accountType) - to start, a user will have no accounts when the BankUser object is created. addAccount will add a new account to the user of the accountType specified. Only one savings/checking account per user, return appropriate error otherwise
Methods getBalance(self, accountType), deposit(self, accountType, amount), and withdraw(self, accountType, amount) for a specific AccountType.
Override __str__ to have an informative summary of user's accounts
In [3]:
class BankUser:
def __init__(self, owner):
self.owner = owner
self.accounts = {}
def addAccount(self, accountType):
if accountType.name in self.accounts:
return False
else:
self.accounts[accountType.name] = BankAccount(self.owner, accountType)
return True
def getBalance(self, accountType):
return len(self.accounts[accountType.name]) if accountType.name in self.accounts else -1
def deposit(self, accountType, amount):
if accountType.name in self.accounts:
return self.accounts[accountType.name].deposit(amount)
else:
return False
def withdraw(self, accountType, amount):
if accountType.name in self.accounts:
return self.accounts[accountType.name].withdraw(amount)
else:
return False
def __str__(self):
s = self.owner + "'s Accounts:\n"
for t, a in self.accounts.items():
s += t + ": " + str(len(a)) + "\n"
return s
Write some simple tests to make sure this is working. Think of edge scenarios a user might try to do.
In [4]:
b = BankUser("Charles Liu")
print(b.deposit(AccountType.SAVINGS, 100))
print(b.addAccount(AccountType.SAVINGS))
print(b.deposit(AccountType.SAVINGS, 50))
In [5]:
print(str(b))
Finally, we are going to rewrite a closure to use our bank account. We will make use of the input function which takes user input to decide what actions to take.
Write a closure called ATMSession(bankUser) which takes in a BankUser object. Return a method called Interface that when called, would provide the following interface:
First screen for user will look like:
Enter Option:
1)Exit
2)Create Account
3)Check Balance
4)Deposit
5)Withdraw
Pressing 1 will exit, any other option will show the options:
Enter Option:
1)Checking
2)Savings
If a deposit or withdraw was chosen, then there must be a third screen:
Enter Integer Amount, Cannot Be Negative:
This is to keep the code relatively simple, if you'd like you can also curate the options depending on the BankUser object (for example, if user has no accounts then only show the Create Account option), but this is up to you. In any case, you must handle any input from the user in a reasonable way that an actual bank would be okay with, and give the user a proper response to the action specified
In [6]:
def ATMSession(bankUser):
def Interface():
option = 0
while option != 1:
try:
option = int(input('Enter Option:\n1)Exit\n2)Create Account\n3)Check Balance\n4)Deposit\n5)WithDraw\n\n'))
if option > 1:
accountOption = 0
while accountOption != 1 and accountOption != 2:
accountOption = int(input('Select Account Type:\n1) Checking\n2) Savings\n'))
if accountOption != 1 and accountOption != 2:
print('Invalid Account Specified\n')
accountType = AccountType.SAVINGS if accountOption == 2 else AccountType.CHECKING
if option == 2:
if bankUser.addAccount(accountType):
print('Account Created\n')
else:
print('Account Already Exists\n')
elif option == 3:
balance = bankUser.getBalance(accountType)
if balance < 0:
print('Account Not Found\n')
else:
print('Balance:{}'.format(balance))
else:
amount = -1
while amount < 0:
amount = int(input('Enter integer amount, cannot be negative\n'))
if amount < 0:
print('Invalid Amount Entered\n')
bankFunc = bankUser.deposit if option == 4 else bankUser.withdraw
if bankFunc(accountType, amount):
print('Transaction was successful\n')
else:
balance = bankUser.getBalance(accountType)
if balance >= 0:
print('Insufficient Funds\n')
else:
print('No Account Found\n')
print(str(bankUser))
except ValueError:
print('Invalid Entry')
option=1
return Interface
In [7]:
interface = ATMSession(b)
In [8]:
interface()