如何创建可以后续访问的类实例?

0 投票
2 回答
2254 浏览
提问于 2025-04-17 20:04

我是一名高中生,刚开始学习编程,对计算机科学很感兴趣。我正在用迈克·道森的书《绝对初学者的Python编程学习(第三版)》自学Python编程。我正在写一个程序来练习我刚学到的面向对象编程(OOP)知识。这个程序模拟了一个银行,玩家可以在里面开银行账户、存取现金、获取汇率、从一个账户转账到另一个账户,还有其他功能。不过,我在这个程序上遇到了很大的困难,主要是关于如何让用户访问多个可用账户的部分。我不太确定这样做是否正确,但我尝试写了一个名为all_accounts的空列表作为类属性。每当创建一个账户时,就把这个账户实例添加到列表里。当玩家选择像存钱或取钱这样的菜单选项时,我想访问列表中的实例,以便修改对象的属性(比如余额)。但我完全不知道该怎么做,已经找了大约三天的答案,但没有找到任何有用的信息。请记住,我还是个初学者,所以我的代码可能写得不太好。我会把整个代码贴在下面,因为我觉得这样大家才能更好地理解代码是如何工作的。如果你发现我代码里有什么不对的地方,或者有什么可以改进的地方,请随时告诉我。我一直很乐意学习。

class Account(object):
    """An interactive bank account"""
    wallet = 0
    all_accounts = []

    # initial
    def __init__(self, ID, bal):
        self.ID = ID
        self.bal = bal
        print("A new account has been opened!")
        Account.all_accounts.append(self)                       

    def withdraw(self, w_input):
        if w_input < self.bal  or w_input == 0:
            print("That is not a valid amount. Sending you back to menu.\n")
            Menu()
        else:
            self.bal = self.bal - w_input
            print("You withdrew $" + str(w_input) + ".\n")
            wallet += w_input
            print("You wallet now contains $" + Account.wallet)
            Menu()

    def deposit(self):
        # Whatever



def Menu():
    print(
        """
0 - Leave the Virtual Bank
1 - Open a new account
2 - Withdraw money
3 - Deposit money
4 - Transfer money from one account to another
5 - Get exchange rates(Euro, Franc, Pounds, Yuan, Yen)
"""
        ) # Add more if necessary
    choice = input("What would you like to do?: ")
    while choice != "0":
        if choice == "1":
            account_name = input("What is your account's ID?: ")
            account_bal = float(input("How much money would you like to put into the account?(USD): "))
            account_name = Account(ID = account_name, bal = account_bal)
            Menu()

        elif choice == "2":
            account_choice = input("What is your account ID?: ")
            if account_choice in instance.Account.all_account:
                withdraw_choice = input("How much money would you like to withdraw?: ")
                account_choice.withdraw(w_input = withdraw_choice)
            else:
                print("Nope.")



    if choice == "0":
        print("\nThank you for visiting the virtual bank!")
        input("Press the [ENTER] key to exit the program.")


Menu()

2 个回答

0

尽量把用户界面和应用程序的核心部分分开,正如ACEfanatic02所说的那样。

想想一个账户需要具备哪些东西:

  • 一个独特的标识符
  • 一个余额
  • 客户的名字
  • 一份交易记录

这些就是实例属性。

还要考虑账户需要能做些什么:

  • 往账户里存钱
  • 从账户里取钱
  • 转账到另一个账户

这些就是方法。

你可能还想要一种方式来打印账户的文本表示。这可以通过给类提供一个特殊的方法 __str__ 来实现。

一个简单的例子:

def _checkamount(a):
    if a < 0:
        raise ValueError('amount must be >0')


class Account(object):

    maxnum = 0

    def __init__(self, client):
        self.client = client
        self.balance = 0.0
        self.transactions = []
        Account.maxnum = Account.maxnum + 1
        self.number = Account.maxnum

    def __str__(self):
        "Generate a human-readable representation of the Account."
        rv = 'Accountnumber: ' + str(self.number) + '\n'
        rv += 'Client: ' + str(self.client) + '\n'
        rv += 'Balance: ' + str(self.balance) + '\n'
        return rv

    def withdraw(self, amount):
        _checkamount(amount)
        if self.balance < amount:
            raise ValueError('overdraft!')
        self.balance -= amount
        self.transactions.append(("withdraw", amount))

    def deposit(self, amount):
        _checkamount(amount)
        self.balance += amount
        self.transactions.append(("deposit", amount))

    def transfer(self, amount, other):
        _checkamount(amount)
        self.balance -= amount
        self.transactions.append(("transfer", amount, other.number))
        other.balance += amount
        other.transactions.append(("transfer", amount, self.number))

我把这段代码保存在一个叫 account.py 的文件里。

一个交互式测试(使用 Ipython,非常推荐用于互动实验):

In [1]: from account import Account

In [2]: a = Account('myself')

In [3]: b = Account('someoneelse')

In [4]: a.deposit(200)

In [5]: a.withdraw(10)

In [6]: b.deposit(50)

In [7]: a.transfer(25, b)

In [8]: print a.transactions
[('deposit', 200), ('withdraw', 10), ('transfer', 25, 2)]

In [9]: print b
Accountnumber: 2
Client: someoneelse
Balance: 75.0

In [10]: print b.transactions
[('deposit', 50), ('transfer', 25, 1)]

In [11]: print a
Accountnumber: 1
Client: myself
Balance: 165.0

In [12]: a.withdraw(1000)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-12-ffc10f6333fe> in <module>()
----> 1 a.withdraw(1000)

/home/rsmith/tmp/account.py in withdraw(self, amount)
     24         _checkamount(amount)
     25         if self.balance < amount:
---> 26             raise ValueError('overdraft!')
     27         self.balance -= amount
     28         self.transactions.append(("withdraw", amount))

ValueError: overdraft!

在这个测试中,我用一个字符串作为 client。由于Python的动态特性,我可以稍后把它改成一个 Client 类,只要这个类有一个 __str__ 方法,代码依然可以正常工作。

0

一般来说,你希望把调用代码和你类内部的工作分开。让 Menu() 函数直接检查存放所有账户的列表,这样做不够灵活,以后可能会出现问题(比如,如果你把列表换成数据库存储怎么办?)

所以,像 AccountManager 这样的类可能是个更好的主意:

class AccountManager(object):
    def __init__(self):
        self.accounts = []

    def create_account(self, id, balance):
        # You may want to check for uniqueness of id's here as well
        account = Account(id, balance)
        self.accounts.append(account)

    def get_account(self, id):
        for account in self.accounts:
            if account.id == id:
                return account
        return None # or a default value, or raise an exception

现在,调用代码只需要告诉 AccountManager 创建和获取账户,而不需要关心它们是怎么存储的。

撰写回答