Python菱形继承问题:Combo类构造函数实现求助
Python菱形继承(钻石继承)构造函数实现方案
业务规则
- Account为基类,包含核心账户属性(
account_id、balance)及基础操作方法(deposit、withdraw) - Transaction类继承Account,扩展交易记录属性(
transaction_history)及交易记录方法,不重写Account核心方法 - Loan类继承Account,重写
withdraw方法(允许超额支取至贷款限额),扩展贷款属性(loan_limit、interest_rate) - Combo类需多继承Transaction与Loan,整合所有类的属性,且优先使用Loan类的重写方法
类结构说明
ERD结构
- 基表:Account(
account_id[主键],balance) - 子表:Transaction(
transaction_id[主键],account_id[外键],transaction_history) - 子表:Loan(
loan_id[主键],account_id[外键],loan_limit,interest_rate) - 关联表:Combo(
combo_id[主键],account_id[外键], 关联Transaction与Loan的所有字段)
UML类图
Account / \ Transaction Loan \ / Combo
- Account:属性
account_id、balance;方法__init__、deposit()、withdraw() - Transaction:继承Account,属性
transaction_history;方法add_transaction() - Loan:继承Account,属性
loan_limit、interest_rate;重写withdraw() - Combo:多继承Transaction与Loan,需整合所有属性,优先调用Loan的重写方法
现有问题代码
以下为用户提供的存在构造函数问题的代码:
class Account: def __init__(self, account_id, balance): self.account_id = account_id self.balance = balance def deposit(self, amount): self.balance += amount return self.balance def withdraw(self, amount): if amount <= self.balance: self.balance -= amount return self.balance raise ValueError("Insufficient balance") class Transaction(Account): def __init__(self, account_id, balance): super().__init__(account_id, balance) self.transaction_history = [] def add_transaction(self, amount, type): self.transaction_history.append({"amount": amount, "type": type}) class Loan(Account): def __init__(self, account_id, balance, loan_limit, interest_rate): super().__init__(account_id, balance) self.loan_limit = loan_limit self.interest_rate = interest_rate def withdraw(self, amount): # 重写:允许超额到贷款限额 if amount <= self.balance + self.loan_limit: self.balance -= amount return self.balance raise ValueError("Exceeds loan limit") # 问题:Combo类无法正确初始化所有属性,且无法优先调用Loan的重写方法 class Combo(Transaction, Loan): pass
解决方案
核心思路
- 调整继承顺序:将Combo的继承顺序改为
Combo(Loan, Transaction),利用Python的MRO(方法解析顺序)优先调用Loan的重写方法 - 构造函数整合属性:通过
super()初始化Loan与Account的属性,手动初始化Transaction的扩展属性(或通过super()链式调用)
修正后的完整代码
class Account: def __init__(self, account_id, balance): self.account_id = account_id self.balance = balance def deposit(self, amount): self.balance += amount return self.balance def withdraw(self, amount): if amount <= self.balance: self.balance -= amount return self.balance raise ValueError("Insufficient balance") class Transaction(Account): def __init__(self, account_id, balance): super().__init__(account_id, balance) self.transaction_history = [] def add_transaction(self, amount, type): self.transaction_history.append({"amount": amount, "type": type}) class Loan(Account): def __init__(self, account_id, balance, loan_limit, interest_rate): super().__init__(account_id, balance) self.loan_limit = loan_limit self.interest_rate = interest_rate def withdraw(self, amount): if amount <= self.balance + self.loan_limit: self.balance -= amount return self.balance raise ValueError("Exceeds loan limit") # 修正后的Combo类 class Combo(Loan, Transaction): def __init__(self, account_id, balance, loan_limit, interest_rate): # 初始化Loan及Account的属性 super().__init__(account_id, balance, loan_limit, interest_rate) # 初始化Transaction的扩展属性(因Transaction的__init__仅依赖Account,可直接初始化) self.transaction_history = [] # 无需重写withdraw,MRO会优先调用Loan的版本
测试用例
def test_combo_account(): # 初始化Combo实例,包含所有属性 combo_acc = Combo("COMBO_001", 1000, 5000, 0.05) # 验证所有属性是否正确初始化 assert combo_acc.account_id == "COMBO_001" assert combo_acc.balance == 1000 assert combo_acc.loan_limit == 5000 assert combo_acc.interest_rate == 0.05 assert combo_acc.transaction_history == [] # 测试Loan的重写withdraw方法(允许超额支取) combo_acc.withdraw(1500) assert combo_acc.balance == -500 # 1000-1500=-500,未超过1000+5000=6000的限额 # 测试Transaction的add_transaction方法 combo_acc.add_transaction(1500, "withdraw") assert len(combo_acc.transaction_history) == 1 assert combo_acc.transaction_history[0]["amount"] == 1500 # 测试继承自Account的deposit方法 combo_acc.deposit(2000) assert combo_acc.balance == 1500 # 测试超出贷款限额的支取 try: combo_acc.withdraw(7000) assert False, "未抛出超出限额异常" except ValueError as e: assert str(e) == "Exceeds loan limit" print("所有测试用例执行通过") test_combo_account()
内容的提问来源于stack exchange,提问作者Harley
相关产品推荐
相关产品推荐

