В обеих ваших deposit()
и widthdraw()
функциях вы фактически никогда не касаетесь переменной, которая удерживает ваш баланс, поэтому вы не видите изменения.
Вы определили переменную balance , но вы ни разу не обновляли это значение с помощью balance = balance - x
. Вы только печатаете результат этой математической операции с str(balance + deposit)
, этот код фактически не изменит ваш баланс.
Чтобы изменить баланс , необходимо обновить глобальную переменную с помощью balance += widthdraw
. Но если вы вставите этот код в свой код, вы получите следующую ошибку:
UnboundLocalError: локальная переменная «баланс», на которую ссылается перед присваиванием
Это связано с тем, что для обновления глобальной переменной внутри функции вам необходимо использовать ключевое слово global , чтобы была сделана ссылка на глобальную переменную. Docs.
Теперь работает следующий код, вот две важные строки:
balance -= withdraw
balance += deposit
Вот как вы на самом деле изменяете значение в переменной balance вместо того, чтобы просто видеть результат математической операции.
balance = 600
def withdraw(): # asks for withdrawal amount, withdraws amount from balance, returns the balance amount
global balance
counter = 0
while counter <= 2:
while counter == 0:
withdraw = int(input("Enter the amount you want to withdraw: AED "))
counter = counter + 1
while ((int(balance) - int(withdraw)) < 0):
print("Error Amount not available in card.")
withdraw = int(input("Please enter the amount you want to withdraw again: AED "))
continue
while ((float(balance) - float(withdraw)) >= 0):
balance -= withdraw
print("Amount left in your account: AED " + str(balance))
return (balance)
counter = counter + 1
def deposit():
global balance
counter = 0
while counter <= 2:
while counter == 0:
deposit = int(input("Enter amount to be deposited: "))
counter = counter + 1
while ((int(balance) + int(deposit)) >= 0):
balance += deposit
print("Amount left in your account: AED" + str(balance))
return balance
counter = counter + 1
withdraw()
deposit()
Отказ от ответственности : Вы можете определенно удалить свои заявления о возврате из снять и депозит , поскольку они практически бесполезны в этом способе решение проблемы. Почему бесполезно? Поскольку глобальная переменная balance изменяется внутри методов. Операторы return были бы полезны, если бы вместо этого вы изменили balance вне методов. Примерно так:
balance = 600
def withdraw(): # asks for withdrawal amount, withdraws amount from balance, returns the balance amount
counter = 0
while counter <= 2:
while counter == 0:
withdraw = int(input("Enter the amount you want to withdraw: AED "))
counter = counter + 1
while ((int(balance) - int(withdraw)) < 0):
print("Error Amount not available in card.")
withdraw = int(input("Please enter the amount you want to withdraw again: AED "))
continue
while ((float(balance) - float(withdraw)) >= 0):
tmp_balance -= withdraw
print("Amount left in your account: AED " + str(tmp_balance))
return tmp_balance
counter = counter + 1
def deposit():
counter = 0
while counter <= 2:
while counter == 0:
deposit = int(input("Enter amount to be deposited: "))
counter = counter + 1
while ((int(balance) + int(deposit)) >= 0):
tmp_balance += deposit
print("Amount left in your account: AED" + str(tmp_balance))
return tmp_balance
counter = counter + 1
balance = withdraw()
balance = deposit()
Вторым способом вы манипулируете значением balance , основываясь на результатах, которые предоставляют вам методы. Разница здесь в том, что когда вы звоните снимать или депозит , вы на самом деле этого не делаете, вы не увидите, как это отразится, пока не сделаете это с balance = withdraw()
. Есть хорошее преимущество в том, чтобы делать это таким образом, чтобы убедиться, что не возникает никаких исключений, и что если снять или депозит полностью завершен на 100%, то вы можете зафиксировать изменения.
Я решил пойти немного дальше в вашем коде, так как у вас, похоже, много кастингов ints , float и циклов while.
Вот пример того, как к нему можно подойти, если он поможет дать кому-то больше идей: (помните, нет единого пути с кодом, мы все кодируем по-разному)
- Используйте декоратор для обработки int () отливок. Вы можете прочитать о декораторах здесь: https://www.python.org/dev/peps/pep-0318/. Когда вы повторили код (почти копирование и вставка), это, как правило, признак применения СУХОГО (не повторяйте себя). Вы можете применить DRY, сняв ответственность с общей функции, которую вы можете вызывать, или с помощью удивительного Python, использовать декораторы. Таким образом, декораторы - это не что иное, как функции, и вы можете «декорировать» их, просто поместив @ decorator_name . Это просто означает, что декоратор будет выполнен до вызова декорированной функции.
- Я не буду приводить к float , потому что в вашем коде вы всегда приводите input к int () . Если это так, то balance никогда не должно быть плавающим.
- Создайте класс с именем ATM, который можно создать с помощью переменной cash_available , которая является наличными в банкомате.
- Удалить фиксированные циклы while (counter = 2), использовать вместо этого один цикл и позволить пользователю выйти по команде.
- Снимите ответственность за ввод данных для метода снятия и дайте пользователю возможность решить, хотят ли они снова снять.
- Поскольку вы используете Python 3, примените
f""
строковый формат.
Итак, теперь код.
def exit_on_input_cast_error(func):
def wrapper(arg):
try:
return func(arg)
except ValueError as ex:
print("Exiting, bye.")
exit()
return wrapper
class ATM():
"""A simple atm machine"""
def __init__(self, balance):
self.cash_available = balance
@exit_on_input_cast_error
def withdraw(self):
'''Withdraws entered amount, until user exits'''
continue_withdraw = True
while continue_withdraw:
withdraw_amount = self._get_withdraw_input()
self.cash_available -= withdraw_amount
self.print_balance("left in")
withdraw_again = str(input("Would you like to withdraw another amount? (Y or N)"))
continue_withdraw = withdraw_again.lower() in ['1', 'y', 'yes']
self.print_bye()
@exit_on_input_cast_error
def _get_withdraw_input(self):
input_error = True
while input_error:
withdrawl = int(input("Enter the amount you want to withdraw (Press N to exit): AED "))
if (self.cash_available - withdrawl) < 0:
print("Error Amount not available in machine.")
input_error = True
elif (self.cash_available - withdrawl) > self.cash_available:
print("Error, you can't withdraw a negative amount.")
input_error = True
else:
input_error = False
return withdrawl
@exit_on_input_cast_error
def deposit(self):
input_error = True
while input_error:
depositing = int(input("Please enter the amount you want to deposit (Press N to exit): AED "))
if (self.cash_available + depositing) < self.cash_available:
print("You cannot deposit a negative amount.")
else:
input_error = False
self.cash_available += depositing
self.print_balance("now in")
self.print_bye()
def print_balance(self, custom_insert = 'in'):
print(f"Amount {custom_insert} your account: AED {self.cash_available}")
def print_bye(self):
print("Thank you for using our services today, bye.")
Давайте пройдёмся понемногу.
Это декоратор.
def exit_on_input_cast_error(func):
def wrapper(arg):
try:
return func(arg)
except ValueError as ex:
print("Exiting, bye.")
exit()
return wrapper
Это всего лишь синтаксис для декоратора. Важной частью является функция возврата (arg) . Это функция, которая будет поймана. Так что этот декоратор просто отвечает за перехват исключения ValueError , которое может быть выдано, когда вы пытаетесь привести что-то вроде int('a')
. Этот декоратор предназначен для предотвращения попыток пользователя вывести или внести строки в банкомат. Поскольку это код, который вы будете использовать как для ввода, так и для ввода, я поместил его в качестве декоратора для простоты вызова (принцип привет DRY).
Далее у нас есть конструктор класса . Я надеюсь, что вы знакомы с классами, если нет, вы можете найти множество ссылок и документации, чтобы понять разницу между class и method , как у вас было первоначально. Самым большим преимуществом в этом случае является то, что вы можете иметь несколько банкоматов с разным количеством наличных денег в каждом. Или вы можете создать экземпляр класса банкомата и настроить его как язык или тип монеты. Вещи, как это.
class ATM():
"""A simple atm machine"""
def __init__(self, balance):
self.cash_available = balance
Вот такой нормальный синтаксис для определения класса. "" "Простой банкомат" "" - это строка документа , поэтому при вызове классов .__ doc __ вы получите это взамен.
Теперь к хорошему.
@exit_on_input_cast_error
def _get_withdraw_input(self):
input_error = True
while input_error:
withdrawl = int(input("Enter the amount you want to withdraw (Press N to exit): AED "))
if (self.cash_available - withdrawl) < 0:
print("Error Amount not available in machine.")
input_error = True
elif (self.cash_available - withdrawl) > self.cash_available:
print("Error, you can't withdraw a negative amount.")
input_error = True
else:
input_error = False
return withdrawl
Этот метод предназначен для обработки получения ввода пользователя. Посмотрите, как оно украшено @ exit_on_input_cast_error ? Это означает, что если пользователь вводит «а», то программа завершает работу. Это происходит потому, что приведение int(...)
сгенерирует исключение ValueError , которое улавливает декоратор. В псевдокоде метод выполняет следующие действия:
while there's an error do the following:
Get the user input and cast it as an int.
Make sure the amount user has introduced matches the following criteria:
It is not more than the cash available in the atm.
It is not a negative number.
Это в основном то, что делает этот метод. Он продолжает просить пользователя ввести верный ввод, пока пользователь не сделает это или не завершит работу, введя «N». И почему они выходят, когда они вводят "N". Поскольку «N» не является int , поэтому, когда приведение происходит в этой строке:
withdrawl = int(input("Enter the amount you want to withdraw (Press N to exit): AED "))
A ValueError будет сгенерировано int () , после чего это исключение будет перехвачено удобным декоратором @exit_on_input_cast_error
, который затем печатает "Bye" и выходит для вас. Круто, верно?
Далее следует фактический метод вывода, который вы использовали . Разница теперь в том, что существует только один цикл, который продолжает спрашивать пользователя, хочет ли он продолжать снятие снова после завершения действия. Пользователь может либо выйти, либо выйти снова.
@exit_on_input_cast_error
def withdraw(self):
'''Withdraws entered amount, until user exits'''
continue_withdraw = True
while continue_withdraw:
withdraw_amount = self._get_withdraw_input()
self.cash_available -= withdraw_amount
self.print_balance("left in")
withdraw_again = str(input("Would you like to withdraw another amount? (Y or N)"))
continue_withdraw = withdraw_again.lower() in ['1', 'y', 'yes']
self.print_bye()
В псевдокоде:
while the user wants to withdraw:
Get the user input
Check that the withdraw action does not result in 0 or negative number.
Print the balance
Ask the user if they want to withdraw again.
По сути, это то, что делает метод. И это используется для новых методов, которые предназначены для печати сообщений.
def print_balance(self, custom_insert = 'in'):
print(f"Amount {custom_insert} your account: AED {self.cash_available}")
def print_bye(self):
print("Thank you for using our services today, bye.")
Эти методы можно вызывать и передавать в пользовательских частях сообщения, например print_balance . Они показывают приватную переменную класса ATM . В методе изъятия я должен указать, что вы можете снимать деньги до точки достижения 0. Машина позволит вам продолжать снимать деньги, но не позволит вам, поскольку в ней 0 наличных.
И, наконец, метод депозита.
@exit_on_input_cast_error
def deposit(self):
input_error = True
while input_error:
depositing = int(input("Please enter the amount you want to deposit (Press N to exit): AED "))
if (self.cash_available + depositing) < self.cash_available:
print("You cannot deposit a negative amount.")
else:
input_error = False
self.cash_available += depositing
self.print_balance("now in")
self.print_bye()
Как видите, очень просто и следует тому же принципу. Вот как бы вы вызывали реальные методы:
atm_a = ATM(600)
atm_a.withdraw()
Вот вывод кода:
Enter the amount you want to withdraw (Press N to exit): AED 100
Amount left in your account: AED 500
Would you like to withdraw another amount? (Y or N)Y
Enter the amount you want to withdraw (Press N to exit): AED -1
Error, you can't withdraw a negative amount.
Enter the amount you want to withdraw (Press N to exit): AED 501
Error Amount not available in machine.
Enter the amount you want to withdraw (Press N to exit): AED 5
Amount left in your account: AED 495
Would you like to withdraw another amount? (Y or N)yes
Enter the amount you want to withdraw (Press N to exit): AED 5
Amount left in your account: AED 490
Would you like to withdraw another amount? (Y or N)no
Thank you for using our services today, bye.
Если вы хотите снять и внести депозит:
atm_a = ATM(600)
atm_a.withdraw()
atm_a.deposit()
Вот вывод кода:
Enter the amount you want to withdraw (Press N to exit): AED 500
Amount left in your account: AED 100
Would you like to withdraw another amount? (Y or N)no
Thank you for using our services today, bye.
Please enter the amount you want to deposit (Press N to exit): AED -1
You cannot deposit a negative amount.
Please enter the amount you want to deposit (Press N to exit): AED 1000
Amount now in your account: AED 1100
Thank you for using our services today, bye.
Обратите внимание, что вы можете внести депозит только один раз, и тогда он существует. Это потому, что я не реализовал это, поскольку я уже сделал это для снимите . Любой желающий может просто скопировать его в депозит , если захочет.
Надеюсь, это было не так уж и много, и мне удалось это объяснить. К этому можно добавить множество вещей:
- Контрольные примеры
- Разница между наличными в банкомате физически и остатком на счете пользователя
- При снятии средств, зная, есть ли у вас правильное количество счетов, чтобы дать желаемую сумму
... и т.д.