Python银行账户系统全解析

发布于:2025-06-19 ⋅ 阅读:(19) ⋅ 点赞:(0)

完整代码如下: 

class BankAccount:
    def __init__(self, account_holder, initial_balance=0):
        """
        初始化银行账户
        :param account_holder: 账户持有人姓名
        :param initial_balance: 初始余额,默认为0
        """
        self.account_holder = account_holder
        self.balance = initial_balance
        self.transactions = []  # 记录交易历史
    
    def deposit(self, amount):
        """
        存款操作
        :param amount: 存款金额
        """    
        if amount <= 0:
            print("存款金额必须大于0")
            return
            
        self.balance += amount
        self.transactions.append(f"存款: +{amount:.2f}")
        print(f"成功存款 {amount:.2f}。当前余额: {self.balance:.2f}")

    def withdraw(self, amount):
        """
        取款操作
        :param amount: 取款金额
        """
        if amount <= 0:
            print("取款金额必须大于0")
            return

        if amount > self.balance:
            print("余额不足,无法完成取款")
            return

        self.balance -= amount
        self.transactions.append(f"取款: -{amount:.2f}")
        print(f"成功取款 {amount:.2f}。当前余额: {self.balance:.2f}")

    def get_balance(self):
        """
        获取当前余额
        """
        return self.balance

    def get_transaction_history(self):
        """
        获取交易历史记录
        """
        return self.transactions

    def __str__(self):
        return f"账户持有人: {self.account_holder}, 当前余额: {self.balance:.2f}"

if __name__ == "__main__":
    name = input("请输入账户持有人姓名: ")
    while True:
        try:
            initial_deposit = float(input("请输入初始存款金额: "))
            if initial_deposit < 0:
                print("初始存款金额不能为负数,请重新输入")
                continue
            break
        except ValueError:
            print("请输入有效的数字")

    # 创建账户
    account = BankAccount(name, initial_deposit)
    print(f"\n账户创建成功!")
    print(account)

    # 循环操作
    while True:
        print("\n请选择操作:")
        print("1. 存款")
        print("2. 取款")
        print("3. 查询余额")
        print("4. 查看交易记录")
        print("5. 退出")  
        
        choice = input("请输入选项(1-5): ")

        if choice == "1":
            # 存款
            while True:
                try:
                    amount = float(input("请输入存款金额: "))
                    if amount <= 0:
                        print("存款金额必须大于0")
                        continue
                    account.deposit(amount)
                    break
                except ValueError:
                    print("请输入有效的数字")

        elif choice == "2":
            # 取款
            while True:
                try:
                    amount = float(input("请输入取款金额: "))
                    if amount <= 0:
                        print("取款金额必须大于0")
                        continue
                    account.withdraw(amount)
                    break
                except ValueError:
                    print("请输入有效的数字")

        elif choice == "3":
            # 查询余额
            print(f"\n当前余额: {account.get_balance():.2f}")
        
        elif choice == "4":
            # 查看交易记录
            print("\n交易记录:")   
            for transaction in account.get_transaction_history():
                print(transaction)
            if not account.get_transaction_history():
                print("暂无交易记录")

        elif choice == "5":
            # 退出
            print("感谢使用银行账户系统,再见!")
            break

        else:
            print("无效的选项,请重新输入")

一、系统框架

  1. 类结构

    • 核心类 BankAccount 封装了银行账户的所有功能
    • 使用面向对象编程(OOP)思想,将数据和操作封装在一起
  2. 主要组件

class BankAccount:
    # 1. 初始化方法
    def __init__(self, account_holder, initial_balance=0)
    
    # 2. 存款功能
    def deposit(self, amount)
    
    # 3. 取款功能 
    def withdraw(self, amount)
    
    # 4. 查询功能
    def get_balance(self)
    def get_transaction_history(self)
    
    # 5. 字符串表示
    def __str__(self)
  1. 用户交互

    • 主程序通过 if __name__ == "__main__": 实现交互式命令行界面
    • 使用 while 循环保持程序持续运行

二、设计思路

  1. 数据建模

    • 账户属性:持有人姓名、余额、交易记录
    • 交易记录使用列表存储,记录每次操作的详细信息
  2. 功能实现原则

    • 单一职责原则:每个方法只做一件事
    • 输入验证:对所有用户输入进行有效性检查
    • 事务记录:自动记录每笔交易的详细信息
    • 防错设计:处理负数金额、余额不足等异常情况
  3. 交互流程

开始 → 输入账户信息 → 主菜单 → 选择操作 → 执行功能 → 返回主菜单 → 退出
  1. 异常处理

  • 使用 try-except 处理非数字输入
  • 使用条件判断处理业务逻辑错误(如余额不足)

三、关键设计点

  1. 状态管理

    • balance 变量实时跟踪账户余额
    • transactions 列表完整记录所有交易历史
  2. 用户友好性

    • 清晰的提示信息
    • 格式化的金额显示(保留两位小数)
    • 操作结果的即时反馈
  3. 扩展性考虑

    • 通过类的方式实现,便于后续添加新功能
    • 交易记录采用标准格式,便于扩展分析功能

四、典型工作流程示例

  1. 用户输入姓名和初始金额
  2. 系统创建账户对象
  3. 用户选择存款:
    • 输入存款金额
    • 系统验证并执行存款
    • 更新余额和交易记录
  4. 用户选择查询:
    • 系统显示当前余额
  5. 用户退出系统

五、代码分析

整体结构分析

该代码定义了一个BankAccount类来模拟银行账户的基本操作,包括初始化账户、存款、取款、查询余额、查看交易记录等功能。在if __name__ == "__main__"模块中,实现了与用户的交互,让用户能够创建账户并进行各种操作。

类定义分析

__init__方法
  • 功能:初始化银行账户对象。
    • 接受account_holder(账户持有人姓名)和initial_balance(初始余额,默认为0)两个参数。
    • 初始化了三个实例变量:self.account_holder(存储账户持有人姓名)、self.balance(存储账户余额)、self.transactions(存储交易历史记录的空列表)。
  • 优点:通过参数初始化实例变量,使每个账户对象在创建时就有明确的初始状态。
deposit方法
  • 功能:实现存款操作。
    • 检查存款金额amount是否小于等于0,若为真,打印提示信息并返回,不进行存款操作。
    • 否则,将存款金额加到账户余额self.balance上,并将存款交易记录(格式为"存款: +{amount:.2f}")添加到self.transactions列表中,同时打印存款成功信息和当前余额。
  • 优点:有输入校验(金额有效性检查),保证了存款操作的合理性,并且及时更新账户余额和记录交易历史。
withdraw方法
  • 功能:实现取款操作。
    • 先检查取款金额amount是否小于等于0,若是,打印提示信息并返回。
    • 再检查取款金额是否大于当前账户余额self.balance,若大于,打印余额不足提示信息并返回。
    • 否则,从账户余额中减去取款金额,并将取款交易记录(格式为"取款: -{amount:.2f}")添加到self.transactions列表中,同时打印取款成功信息和当前余额。
  • 优点:具备完善的输入校验(金额有效性和余额充足性检查),确保取款操作符合实际业务逻辑,保护账户资金安全。
get_balance方法
  • 功能:简单返回当前账户的余额self.balance
  • 优点:提供了一种便捷的方式获取账户余额,符合面向对象编程中封装的思想(外部通过方法访问内部数据)。
get_transaction_history方法
  • 功能:返回存储交易历史记录的self.transactions列表。
  • 优点:方便用户查看账户的交易明细,是对账户操作历史的记录和展示。
__str__方法
  • 功能:定义了对象的字符串表示形式。当使用print()函数打印账户对象时,会自动调用该方法,返回一个包含账户持有人姓名和当前余额的字符串(格式为"账户持有人: {self.account_holder}, 当前余额: {self.balance:.2f}")。
  • 优点:使账户对象在打印时能以友好、易读的方式呈现信息,方便用户直观了解账户基本情况,也有利于调试和日志记录等场景。

if __name__ == "__main__"模块分析

  • 获取用户输入并创建账户
    • 使用input()函数获取用户输入的账户持有人姓名name
    • 通过循环和try-except块,确保用户输入的初始存款金额initial_deposit是有效的数字且不为负数,然后创建BankAccount对象account
    • 打印账户创建成功信息和账户对象(调用__str__方法)。
  • 用户操作循环
    • 进入一个无限循环,展示操作菜单(存款、取款、查询余额、查看交易记录、退出)。
    • 根据用户输入的选项choice,执行相应的操作(调用BankAccount类的对应方法)。
    • 对于每个操作(如存款、取款),同样使用循环和try-except块确保用户输入的金额是有效的数字,并进行相应的业务逻辑处理(调用类方法)。
    • 若用户选择退出(选项5),打印感谢信息并终止循环,结束程序。

代码优点总结

  • 面向对象封装:将账户相关的数据(余额、交易记录、持有人姓名等)和操作(存款、取款等)封装在BankAccount类中,体现了良好的面向对象设计思想,使代码结构清晰,便于维护和扩展。
  • 输入校验完善:在存款、取款等操作中,对用户输入的金额进行了充分的有效性检查(如金额是否为正数、取款时余额是否足够等),增强了程序的健壮性,避免了不合理操作导致的错误。
  • 交互友好:通过清晰的菜单提示和操作反馈(如打印存款、取款成功信息和当前余额等),使用户能够方便、直观地与程序进行交互,了解操作结果。

六、__init____str__是两个特殊的魔法方法

1. __init__ 方法

核心作用:
  • 构造函数:在创建类实例时自动调用
  • 初始化对象:设置对象的初始状态
银行账户示例:
class BankAccount:
    def __init__(self, account_holder, initial_balance=0):
        self.account_holder = account_holder  # 设置账户持有人
        self.balance = initial_balance        # 设置初始余额
        self.transactions = []                # 初始化交易记录
关键特点:
  • 第一个参数必须是self(指向新创建的对象)
  • 在实例化时自动执行:
account = BankAccount("张三", 1000)  # 自动调用__init__
  • 不能有返回值(隐式返回None

2. __str__ 方法

核心作用:
  • 定义对象的字符串表示:当使用print()str()时自动调用
  • 提供用户友好描述:便于调试和输出
银行账户示例:
def __str__(self):
    return f"账户持有人: {self.account_holder}, 当前余额: {self.balance:.2f}"
使用场景:
account = BankAccount("李四", 500)
print(account)  # 自动调用__str__,输出:账户持有人: 李四, 当前余额: 500.00
关键特点:
  • 必须返回字符串类型
  • 如果没有定义__str__,Python会使用__repr__作为备用
  • 常用于日志、用户界面等需要可读输出的场景

3. 对比总结

特性 __init__ __str__
调用时机 创建实例时 调用print()str()
主要用途 初始化对象属性 定义对象的可读字符串表示
返回值 不应返回任何值 必须返回字符串
是否必需 非必需(但绝大多数类都会实现) 非必需(但建议重要类都实现)
示例调用场景 obj = ClassName(args) print(obj) 或 str(obj)

4. 实际应用关系

在银行账户系统中,这两个方法协同工作:

# 创建账户(调用__init__)
account = BankAccount("王五", 2000)  

# 查看账户信息(调用__str__)
print(account)  
# 输出:账户持有人: 王五, 当前余额: 2000.00

5. 为什么需要它们?

  • __init__: 确保对象创建后即处于有效状态,避免后续出现属性未定义的错误

  • __str__: 提供比默认内存地址(如<__main__.BankAccount object at 0x...>)更有意义的输出

6. 进阶提示

  1. 类似方法__repr__:用于开发者调试,应返回明确的创建表达式

def __repr__(self):
    return f'BankAccount("{self.account_holder}", {self.balance})'
  1. 在银行账户系统中,良好的__str__实现可以帮助:

    • 快速查看账户状态
    • 生成对账单摘要
    • 调试交易记录

七、__str__方法的语言规范

  1. 必须返回字符串 Python明确规定__str__方法必须返回一个字符串对象str类型)。当调用print(obj)str(obj)时,解释器会自动执行这个方法并显示其返回值。

  2. print()的协作机制

print(account)  # 内部实际执行:
               # 1. 调用account.__str__()
               # 2. 打印该方法返回的字符串

3.银行账户示例解析

def __str__(self):
    return f"账户持有人: {self.account_holder}, 当前余额: {self.balance:.2f}"
  • 返回值内容: 返回一个格式化的字符串,包含账户持有人和带两位小数的余额 (例如:"账户持有人: 张三, 当前余额: 1000.00"

  • 技术细节

    • f"...":f-string格式化字符串(Python 3.6+)
    • :.2f:将浮点数格式化为2位小数

4.如果不返回字符串会发生什么?

错误示例

def __str__(self):
    print("账户信息...")  # 错误!__str__不应该直接打印
  • 调用print(account)会导致: TypeError: __str__ returned non-string (type NoneType)

正确做法: 必须通过return返回字符串,让调用者决定如何处理这个字符串。

5.为什么不是直接打印?

这种设计体现了关注点分离原则:

  1. __str__的职责: 只负责生成对象的字符串表示形式 (不关心这个字符串是用来打印、记录日志还是其他用途)

  2. 调用方的自由: 返回字符串后,调用者可以:

# 选择1:直接打印
print(account)

# 选择2:存入文件
with open("log.txt", "a") as f:
    f.write(str(account))

# 选择3:拼接其他字符串
msg = "账户状态:" + str(account)

6.类比其他语言

语言 类似机制
Java toString() 方法
C# ToString() 方法
JavaScript toString() 原型方法
C++ 重载 << 操作符

八、while True 语句、 if elif else 语句和 try except 语句的详细介绍

while True 语句

  • 作用:创建一个无限循环,只要条件 True 始终满足(实际上就是一直满足),循环体就会不断执行。通常需要在循环内部通过 break 语句来终止循环。
  • 语法结构
while True:
    # 循环体代码
    if 终止条件:
        break
  • 示例
while True:
    user_input = input("请输入一个数字(输入 'q' 退出): ")
    if user_input == 'q':
        break
    try:
        num = int(user_input)
        print(f"你输入的数字是: {num}")
    except ValueError:
        print("输入无效,请输入一个整数。")
  • 应用场景
    • 创建交互式程序,如命令行工具,等待用户持续输入指令,直到用户发出退出信号(如上述示例)。
    • 需要持续监听某种状态(如服务器监听客户端连接请求)的场景。

if elif else 语句

  • 作用:用于条件判断,根据不同的条件执行相应的代码块。if 后面可以跟多个 elif(表示“否则如果”),最后可以有一个可选的 else(表示前面条件都不满足时执行)。
  • 语法结构
if 条件1:
    # 条件1满足时执行的代码
elif 条件2:
    # 条件2满足时执行的代码
else:
    # 前面条件都不满足时执行的代码
  • 示例
score = 85
if score >= 90:
    print("优秀")
elif score >= 80:
    print("良好")
elif score >= 60:
    print("及格")
else:
    print("不及格")
  • 应用场景
    • 根据不同的数值范围、逻辑条件执行不同操作,如成绩等级判断(如上例)。
    • 处理不同用户角色的权限逻辑(如判断用户是管理员、普通用户等,执行不同的功能)。

try except 语句

  • 作用:用于捕获和处理程序运行时可能出现的异常,防止程序因为异常而崩溃。try 块中放置可能引发异常的代码,except 块用于处理捕获到的异常。
  • 语法结构
try:
    # 可能引发异常的代码
except 异常类型:
    # 处理异常的代码
  • 示例
try:
    result = 10 / 0  # 会引发 ZeroDivisionError 异常
except ZeroDivisionError:
    print("除数不能为零!")
  • 场景
    • 处理用户输入可能不符合预期的情况(如尝试将用户输入转换为特定类型时,用户输入了非数字字符)。
    • 进行文件操作、网络请求等可能失败的操作时,捕获并处理相应的异常(如文件不存在 FileNotFoundError、网络连接超时等)。

在实际编程中,这三种语句经常结合使用。例如在银行账户系统代码里:

while True:
    try:
        initial_deposit = float(input("请输入初始存款金额: "))
        if initial_deposit < 0:
            print("初始存款金额不能为负数,请重新输入")
            continue
        break
    except ValueError:
        print("请输入有效的数字")

这里 while True 创建了一个循环让用户不断输入,直到输入有效(通过 break 终止循环)。try except 用于处理用户输入不是数字的情况(捕获 ValueError 异常),if 语句用于进一步校验输入数字的合理性(是否为负数)。

再比如在取款操作的代码中:

elif choice == "2":
    # 取款
    while True:
        try:
            amount = float(input("请输入取款金额: "))
            if amount <= 0:
                print("取款金额必须大于0")
                continue
            account.withdraw(amount)
            break
        except ValueError:
            print("请输入有效的数字")

九、breakcontinue 是用于控制循环流程的关键字

作用和功能

  • break
    • 作用:直接终止当前所在的循环(可以是 for 循环或 while 循环),循环体中 break 语句之后的代码将不再执行,程序会跳出循环,继续执行循环后面的代码。
    • 示例
for i in range(10):
    if i == 5:
        break
    print(i)
# 输出结果为 0 1 2 3 4,当 i 等于 5 时,循环终止
  • continue
    • 作用:跳过本次循环中 continue 语句之后的代码,直接进入下一次循环的条件判断(对于 for 循环,会继续迭代下一个元素;对于 while 循环,会继续判断循环条件)。
    • 示例
for i in range(10):
    if i % 2 == 0:
        continue
    print(i)
# 输出结果为 1 3 5 7 9,当 i 是偶数时,跳过本次循环的打印操作,直接进入下一次循环

适用场景

  • break
    • 当你在循环中发现某个特定条件满足,并且后续不需要再执行循环中的任何操作时,就可以使用 break 来提前结束循环。例如在一个列表查找元素的循环中,一旦找到目标元素,就可以用 break 停止继续查找。
    • 示例
my_list = [10, 20, 30, 40, 50]
target = 30
for num in my_list:
    if num == target:
        print(f"找到目标元素 {target}")
        break

continue

  • 当你希望在满足某些条件时,跳过本次循环的一部分操作,但循环还需要继续执行下去时,适合使用 continue。比如在遍历一个数字列表时,想忽略其中的偶数,只对奇数进行某些计算或处理。
  • 示例
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for num in numbers:
    if num % 2 == 0:
        continue  # 跳过偶数
    # 以下是对奇数的处理逻辑
    print(f"处理奇数: {num}")

对循环嵌套的影响

  • break:在循环嵌套的情况下,break 只会终止它所在的那一层循环。
    • 示例
for i in range(5):
    for j in range(5):
        if j == 2:
            break  # 只会跳出内层的 j 循环
        print(f"i={i}, j={j}")
# 输出结果是 当 j 等于 2 时,内层循环停止,外层循环继续
  • continue:同样在循环嵌套中,continue 也只影响它所在的那一层循环,会跳过该层循环中 continue 后面的代码,进入该层循环的下一次迭代。
    • 示例
for i in range(5):
    for j in range(5):
        if j == 2:
            continue  # 跳过内层 j 循环中 j=2 时后续的代码,继续 j 的下一次循环
        print(f"i={i}, j={j}")
# 输出结果是 当 j 等于 2 时,跳过本次 j 循环的打印操作,j 继续递增

总的来说,break 用于快速结束循环,continue 用于有条件地跳过循环体中的部分代码,它们为程序员提供了灵活控制循环流程的手段。


网站公告

今日签到

点亮在社区的每一天
去签到