Python Classes & OOP
Apply your skills with a real-world coding challenge. Try to solve it yourself first!
Coding Challenge: Secure Bank Transaction Processor
Difficulty Level
Intermediate
Problem Description
Imagine you're building a highly resilient, professional-grade banking application. Your task is for build a BankAccount class that processes an account withdrawal using Object-Oriented Programming (OOP) principles.
Instead of writing simple script that might crash than bad inputs or generic errors, you need to build a class blueprint that gracefully handles failure states documents its own business logic. Guarantees no system resources are left hanging, and you will simply accomplish this by bundling the data with internal methods that use a robust 4-step exception handling architecture (try except else finally), custom exceptions, and developer assertions.
You've got to write a class with the withdraw method that:
1. Validates that the withdrawal amount is actually purely a positive number using assertions to catch developer mistakes early.
2, while attempts to process the transaction inside a try block, raising a custom InsufficientFundsError if the user tries for withdraw more money than they have really.
3. Separates a dangerous transaction logic from the safe success processing (like generating the receipt) by utilizing an else block.
4. Always cleanly shuts down simulated database connection inside the finally block, regardless with whether the code succeeds, fails, or panics.
Input & Output Specifications
- Input:
initial_balance(float or int): Passed into the__init__method to set up the account.withdrawal_amount(float or int): Passed into thewithdrawmethod.- Output:
- Returns the updated account balance (or the original balance if the transaction failed).
- Must print specific console messages:
- error message when an
InsufficientFundsErroroccurs. - A receipt/success message when the transaction is successful (only if no exceptions were raised).
- A cleanup message indicating a database connection is safely closed (must happen every single time).
Starter Code Boilerplate
class InsufficientFundsError(Exception):
"""Custom exception for self-documenting business logic."""
pass
class BankAccount:
def __init__(self, initial_balance):
self.balance = initial_balance
def withdraw(self, amount):
# Simulated database connection flag
db_connection_open = True
print("Opening database connection...")
# TODO: Use the assert keyword to crash early if 'amount' is <= 0
try:
# TODO: Write the logic to check if the balance is sufficient.
# If not, raise the InsufficientFundsError.
# Otherwise, deduct the amount from self.balance.
pass
except InsufficientFundsError as e:
# TODO: Handle the custom exception gracefully and print an error message.
pass
else:
# TODO: Print a success message / receipt. This runs ONLY if the try block succeeds.
pass
finally:
# TODO: Safely shut down the simulated database connection and print a cleanup message.
pass
return self.balance
Hints
- The
__init__andselfsynergy: Useself.balanceinside your methods so your internal tools can seamlessly talk to data bundled inside the instantiated object. - Catching Developer Bugs: Use
assert amount > 0to actively crash the program if a developer mistakenly passes the negative withdrawal amount. Assertions are specifically for debugging during development, not for catching user errors. - Custom Exceptions: Using standard built-in errors like
ValueErrorfor low balance is too vague. Throwing your customInsufficientFundsErrormakes your class immediately self-documenting. - The
elseSuperpower: Don't stuff too much code into yourtryblock. Put the deduction math inside thetryblock but put the safe receipt generation inside optionalelseblock, while it runs only if atryblock completes without issues. - Closing the Door: Whether the logic succeeds, fails, or panics the
finallyblock runs no matter what; use it to setdb_connection_open = Falseand print your simulated cleanup message ensuring your object safely manages resources without memory leaks.
Test Cases
Use the following test cases to verify your class works correctly.
Test Case 1: Successful Transaction
* Input: account = BankAccount(100) followed by account.withdraw(40)
* Expected Output: Deducts 40 prints the success receipt out of else block, prints database closed message than a finally block, and returns 60.
Test Case 2: Insufficient Funds
* Input: account = BankAccount(50), followed by account.withdraw(100)
* Expected Output: Triggers the custom InsufficientFundsError, prints the exact error message from the except block, prints the database closed message from the finally block, and returns an original balance of 50.
Test Case 3: Developer Error (Negative Amount)
* Input: account = BankAccount(100) followed by account.withdraw(-20)
* Expected Output: The program violently crashes with an AssertionError before the try block even starts, indicating a developer tried for pass bad data.
Verify Your Solution
Write your solution in the compiler, run it to verify output, then click below to verify.