首页 > 解决方案 > OOP:如何编写类之间的pythonic交互?

问题描述

我想对两个类之间的交互进行建模,其中一个类将另一个类作为其方法之一中的参数。哪个类应该在另一个类的方法的参数中?

我已经为该问题编写了两种替代解决方案,但我不确定其中哪一种被认为是处理此问题的正确方法。也许还有更好的方法,但这是我的两个选择:

class BankAccount:

    def __init__(self, balance):
        self._balance = balance

    def transaction(self, cash):
        self._balance += cash._value
        cash._value = 0


class Cash:

    def __init__(self, value):
        self._value = value

    def transfer(self, bank_account):
        bank_account._balance += self._value
        self._value = 0


if __name__ == "__main__":

# First alternative
    acc = BankAccount(balance=100)
    cash = Cash(value=10)

    print('-' * 30)
    print('First alternative')
    print(f'Account balance before: {acc._balance}')
    print(f'Cash value before: {cash._value}')
    acc.transaction(cash=cash)
    print(f'Account balance after: {acc._balance}')
    print(f'Cash value after: {cash._value}')

# Second alternative
    acc = BankAccount(balance=100)
    cash = Cash(value=10)

    print('-' * 30)
    print('Second alternative')
    print(f'Account balance before: {acc._balance}')
    print(f'Cash value before: {cash._value}')
    cash.transfer(bank_account=acc)
    print(f'Account balance after: {acc._balance}')
    print(f'Cash value after: {cash._value}')

正如您所看到的,这两种替代方案都显示了相同的结果,但我很高兴获得对这种类交互建模的 Pythonic 方式的建议。谢谢。

标签: pythonoop

解决方案


该示例格式不正确,这使我们无法专注于实际的 OOP。一些现金因为被转移而失去价值是没有意义的。一张 20 美元的钞票是否会因为您将其存入银行而失去其价值?

一个新的例子

相反,让我们考虑表示两个银行账户之间的资金转移的问题。

OOP 的一个关键概念是不应直接更新实例的属性。相反,实例应该通过提供对其状态进行一些控制的方法来提供 API。

我们可以通过定义方法depositwithdrawBankAccount. 这样,我们就可以定义transfer_to只使用这个 API 的方法。

class BankAccount:
    def __init__(self):
        self.balance = 0

    def deposit(self, amount):
        self.balance += amount

    def withdraw(self, amount):
        if amount >= self.balance:
            self.balance -= amount
        else:
            raise ValueError('Insufficient funds')

    def transfer_to(self, target, amount):
        if isinstance(target, BankAccount):
            self.withdraw(amount)
            target.deposit(amount)
        else:
            raise ValueError("'target' must be another BankAccount")

优势

通过封装和的逻辑withdraw,我们允许通过继承简单地实现更复杂的账户类型。deposittranfer_to

BankAccount在这里,让我们举一个允许负余额的新型示例。

class CreditAccount(BankAccount):
    def withdraw(self, amount):
        self._balance -= amount

通过将提款的责任完全委托给 的实例BankAccount,我们允许外部代理在无需了解提款和存款的内部逻辑的情况下操纵账户。


推荐阅读