【问题标题】:How not to get a repeated attribute of an object?如何不获取对象的重复属性?
【发布时间】:2021-06-02 03:34:44
【问题描述】:

我想制作一种“注册系统”,但在银行使用对象,因此您作为客户必须创建您的帐户,因此,您不能拥有与其他客户相同的名称(用户名)。

我试过这个:

class Account:
    def __init__(self, name, pin, balance):
        self.name = name
        self.pin = pin
        self.balance = balance

    def __get_name__(self):
        return self.name

    def __set_name__(self, name):
        self.name = name

    def __get_pin__(self):
        return self.pin

    def __set_pin__(self, pin):
        self.pin = pin

    def __get_balance__(self):
        return self.balance

    def __set_balance__(self, balance):
        self.balance = balance

    def _deposit(self, deposition_amount):
        self.balance += deposition_amount

    def _withdraw(self, withdrawal_amount):
        self.balance -= withdrawal_amount

set_of_accounts = set()

def create_account():
    name = input("Input name : ")
    for account in set_of_accounts:
        if account.__get_name__() == name:
            print('There is other account with same name, try a new one')
        else:
                pin = str(input("Please input a pin of your choice : "))
                balance = eval(input("Please input a amount to deposit to start an account : "))

                account = Account(name, pin, balance)
                set_of_accounts.add(account)

                print("\n----New account created successfully !----")
                print("Note! Please remember the Name and Pin")
                print("========================================")

def print_all_customers():
    print("Customer name list and balances mentioned below : \n")

    if len(set_of_accounts) > 0:
        for account in set_of_accounts:
            print("->. Customer = " + str(account.__get_name__()))
            print("->. Balance = " + str(account.__get_balance__()) + " -/Rs\n")
    else:
        print("No accounts are persisted yet.\n")
    input("Please press enter key to go back to main menu to perform another function or exit ...")

def menu():
    while True:
        print("*************************************")
        print("=<< 1. Open a new account         >>=")
        print("=<< 2. Withdraw Money             >>=")
        print("=<< 3. Deposit Money              >>=")
        print("=<< 4. Check Customers & Balance  >>=")
        print("=<< 5. Exit/Quit                  >>=")
        print("*************************************")
        choiceNumber = input("Select your choice number from the above menu : ")
        if choiceNumber == "1":
            create_account()
        elif choiceNumber == "2":
            pass
        elif choiceNumber == "3":
            pass
        elif choiceNumber == "4":
            print_all_customers()
        elif choiceNumber == "5":
            exit()
        else:
            print("Invalid option")

menu()

我的问题出在create_account() 中,因为在我写下名称后,程序没有进入 for 循环。所以我迷路了,因为我不知道为什么不执行 for 循环。 我希望有人可以帮助我,如果您有其他想法,我接受建议。

【问题讨论】:

  • 如果帐户集为空。你认为 for 循环将如何执行?您需要添加一个特殊条件来检查集合是否为空。
  • 您不需要单独的 for 循环:if any(acc.__get_name__() == name) for acc in set_of_accounts):
  • dunder 方法是怎么回事? __names_like_this__ 为 Python 核心语言和标准库保留。 __set_name__ 特别是 already used 用于描述符功能。
  • 你用的是什么版本的python?

标签: python for-loop object oop set


【解决方案1】:

问题在于create_account 方法内部的循环,这也因使用dunder 方法而复杂化。在我们修复 create_account 方法之前,我建议重构 Account 类,以便该类更清晰。然后继续创建一个类来处理检查帐户是否已创建。然后修复create account方法。

邓德法

Dunder 方法或双下划线方法是不打算直接调用的特殊或魔术方法。 __init__ 方法就是一个例子。

如果我们要创建一个新的帐户对象,我们不直接调用__init__,而是调用Account(),那么python 将在后台调用__init__,这样可以保持代码更简洁,因为我们没有init 函数调用散布在代码中,我们看到Account() 更清晰。 Python 为许多事情执行此操作,例如 == 调用 dunder 方法 __eq__

因为方法上的 __ 会让人们感到困惑,并且会给你的程序带来不必要的副作用,所以我们应该从你的方法中清除所有的 __。

另一个约定是单下划线,这习惯于变量是私有的。因为您从 Account 类外部调用 _deposit 和 _withdraw 方法,所以将单个下划线转换为一些“私有变量”。这样做的主要原因是类型提示,所以让我们对整个类进行类型提示。

通过这些更改,帐户类将如下所示:

class Account:

    _name: str
    _pin: str
    _balance: int

    def __init__(self, name: str, pin: str, balance: int):
        self._name = name
        self._pin = pin
        self._balance = balance

    def get_name(self) -> str:
        return self._name

    def set_name(self, _name):
        self._name = _name

    def get_pin(self) -> str:
        return self._pin

    def set_pin(self, _pin: str):
        self._pin = _pin

    def get_balance(self) -> int:
        return self._balance

    def set_balance(self, balance: int):
        self._balance = balance

    def deposit(self, deposition_amount: int):
        self._balance += deposition_amount

    def withdraw(self, withdrawal_amount: int):
        self._balance -= withdrawal_amount

帐户检查器

更改帐户的存储方式将使检查帐户是否存在变得更加容易。为此,让我们创建一个 Bank 类来跟踪程序中的所有帐户。

 class Bank:

    accounts: dict

    def __init__(self):
        self.accounts = dict()

    def __contains__(self, account: Account) -> bool:
        return account.get_name() in self.accounts.keys()

    def __iter__(self):
        return self.accounts.values().__iter__()

    def empty(self) -> bool:
        return len(self.accounts) < 1

    def name_taken(self, name: str) -> bool:
        return name in self.accounts.keys()

    def create_account(self, name: str, pin: str, balance: int):
        self.accounts[name] = Account(name, pin, balance)

如您所见,Bank 类将所有帐户存储在字典中。字典很像列表,而是通过整数访问列表中的对象,字典通过另一个对象(键)访问对象。

dunder 方法__init__ 是一个普通的指挥者,它只是建立一个字典来保存程序中的所有帐户。

dunder 方法 __iter__ 允许我们在 for 循环中使用 bank,例如for account in bank:。当我们遍历银行对象时,我们想要遍历字典中存储的所有值。

空方法检查字典是否有任何项目。

name_taken 检查是否有任何与传入的名称匹配的键。如果它们匹配,我们就知道该名称已被使用,我们不能使用它。

创建帐户允许我们只传递帐户的组件并正确创建并正确放置在字典中。

修复创建帐户

通过这两项更改,修复 create_account 会容易得多。

首先让我们看看出错的代码:

def create_account():
    name = input("Input name : ")
    for account in set_of_accounts:
        if account.__get_name__() == name:
            print('There is other account with same name, try a new one')
        else:
                pin = str(input("Please input a pin of your choice : "))
                balance = eval(input("Please input a amount to deposit to start an account : "))

                account = Account(name, pin, balance)
                set_of_accounts.add(account)

                print("\n----New account created successfully !----")
                print("Note! Please remember the Name and Pin")
                print("========================================")

假设我们输入“Sam”作为输入,并且在 set_of_accounts 中有零个帐户。 name 将设置为 'Sam',但由于 set_of_accounts 为空,因此不会运行 for 循环中的任何内容。

再次想象一下,我们输入“Sam”作为输入输入,并且在 set_of_accounts 中有许多帐户。然后,每当“Sam”没有名称不是“Sam”的帐户时,我们都会尝试创建一个新帐户。

我们应该注意的另一件事是在迭代同一集合时编辑集合。在for account in set_of_accounts: 中通过set_of_accounts.add(account) 编辑set_of_accounts 可能会给我们带来不正确的行为。

以这种方式思考程序告诉我们,与其在循环中进行检查,我们希望进行一次检查并在帐户不存在时创建一个帐户,或者如果它已被占用则要求另一个名称。

这些更改 create_account 如下所示:

def create_account():
    name = input("Input name : ")

    # keep asking for a new name if the name still exists
    while bank.name_taken(name):
        name = input('There is other account with same name, try a new one:')

    pin = str(input("Please input a pin of your choice : "))
    balance = read_integer("Please input a amount to deposit to start an account : ")

    bank.create_account(name, pin, balance)

    print("\n----New account created successfully !----")
    print("Note! Please remember the Name and Pin")
    print("========================================")

我们可以看到create_account 现在对每个名称进行一次检查。一旦名称是唯一的,它将继续读取密码和余额,然后通过create_account 方法创建一个新帐户。

A fully working version of your refactored code can be found here.

如果您有任何问题,请给我留言。

【讨论】:

  • print_all_customers() 中迭代bank 对象以打印所有帐户或者这就是我所理解的,但我想知道为什么不能直接将self.accounts 字典迭代到打印所有帐户? @user1239299
  • self.accounts.__iter__() 会给我们一个迭代器,它会返回一个 (, ) 对。当我们想要列出所有帐户时,我们只关心 Account 对象,因此迭代仅包含帐户的字典的值是有意义的。但什么是迭代器?迭代器是一个在 for 循环中跟踪当前项目的对象; for 循环是否可以继续循环等。字典、列表和其他集合没有用于循环的 neccary 数据/方法。 __iter__ 在我们想要循环时被调用,所以我们必须返回一个迭代器而不是一个集合
【解决方案2】:

你只需要在你的代码中做一点调整,你应该再创建一个set object 名称name,它就像银行中的register of name。所以将create_account函数代码更新为最后一个代码。

更新:

set_of_accounts = set()

def create_account():
    name = input("Input name : ")
    for account in set_of_accounts:
        if account.__get_name__() == name:
            print('There is other account with same name, try a new one')
        else:
                pin = str(input("Please input a pin of your choice : "))
                balance = eval(input("Please input a amount to deposit to start an account : "))

                account = Account(name, pin, balance)
                set_of_accounts.add(account)

                print("\n----New account created successfully !----")
                print("Note! Please remember the Name and Pin")
                print("========================================")

收件人:

set_of_accounts = set()
names = set()
def create_account():
    name = input("Input name : ")
    if name in names:
            print('There is other account with same name, try a new one')
    else:
                pin = str(input("Please input a pin of your choice : "))
                balance = eval(input("Please input a amount to deposit to start an account : "))

                account = Account(name, pin, balance)
                set_of_accounts.add(account)
                names.add(name)
                print("\n----New account created successfully !----")
                print("Note! Please remember the Name and Pin")
                print("========================================")

【讨论】:

    猜你喜欢
    • 2011-09-12
    • 1970-01-01
    • 2020-01-30
    • 2017-05-21
    • 2013-06-25
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 2016-07-16
    相关资源
    最近更新 更多