I am creating an ATM using python code, and I need to create deposit and withdraw functions that behave just like an ATM would. Separately, the deposit and withdraw functions work. However, when I withdraw first then deposit, the balance does not update. Same thing when I deposit then withdraw.
Thank you and your help is much appreciated.
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):
print("Amount left in your account: AED" + str(balance - withdraw))
return (balance - withdraw)
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):
print("Amount left in your account: AED" + str(balance + deposit))
return (balance + deposit)
counter = counter + 1
withdraw()
deposit()
If I withdraw 17, the balance will be 583. However, when I deposit 12, the balance becomes 612, which is wrong it should be 595.
You are not changing the "balance" variable at all! Your code should like something like:
balance = withdraw()
balance = deposit()
But there are multiple other problems with your code. First of all you should not do that many casts. You have to convert your user input one time to a number, then just calculate everything with that type. Your are using float and int. If you want to stuff with currency, you should use probably decimal ( https://docs.python.org/2/library/decimal.html ), because floating point arithmetic is not exact for some special cases (you need to round) and integer does obviously not provide floating point arithmetic.
Also your special 'while' usage does not fit common coding standards and makes your code hard to read. Better write one function to get user input and seperate it from the withdrawal() and deposit() logic.
EDIT: Since you seem to be a beginner, I will provide a minimal working solution.
import decimal
balance = 600
def get_user_input(action):
# Get user input and convert it to decimal type
return decimal.Decimal(input("Please enter amount to {} from your account: ".format(action)))
def withdraw():
amount = get_user_input("withdraw")
return balance - amount
def deposit():
amount = get_user_input("deposit")
return balance + amount
print("Your Balance is {} AED".format(balance))
balance = withdraw()
balance = deposit()
print("Your Balance is {} AED".format(balance))
You just forgot to save the new balance, you just print it out
balance = 600
def withdraw(): # asks for withdrawal amount, withdraws amount from balance, returns the balance amount
while True:
withdraw = int(input("Enter amount to be withdrawn: "))
if withdraw > balance:
print("Error Amount not available in card.")
else:
new_balance = balance - withdraw
print("Amount left in your account: AED" + str(new_balance))
return (new_balance)
def deposit():
deposit = int(input("Enter amount to be deposited: "))
new_balance = balance + deposit
print("Amount left in your account: AED" + str(new_balance))
return (new_balance)
# This is the only place you HAVE to change for it to work
balance = withdraw()
balance = deposit()
Took the freedom to change it a bit, but most importantly, you should save the new balance.
I also suggest to make the integer conversion safer, by checking if it is an int before converting it to one.
withdraw_string = input("Enter amount to be withdrawn: ")
try:
withdraw_int = int(withdraw_string)
is_int = True
except ValueError:
print("INVALID INPUT")
is_int = False
if is_int == True:
In both your deposit()
and widthdraw()
functions, you are never actually touching the variable that holds your balance, that's why you don't see the change.
You have defined the variable balance yet at no point do you ever update that value with balance = balance - x
. You are only printing the outcome of that math operation with str(balance + deposit)
, that code won't actually change your balance.
In order to change your balance you need to update that global variable with balance += widthdraw
. But if you put that code in your code, you will get the following error:
UnboundLocalError: local variable 'balance' referenced before assignment
That is because in order to update a global variable from inside a function you need to use the global keyword so that a link is made to the global variable. Docs.
The following code now works, the two important lines are these:
balance -= withdraw
balance += deposit
That's how you are actually modifying the value in the balance variable instead of just seeing the output of the math operation.
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()
Disclaimer : You can most definitely remove your return statements from withdraw and deposit since they are essentially useless in this way of solving the problem. Why useless? Because the global variable balance gets modified inside the methods. The return statements would be useful if instead you modified the balance outside the methods. Something like this:
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()
In this second way, you are manipulating the value of balance based on the returns that the methods provide you. The difference here is that when you call withdraw or deposit you are not actually carrying that out, you won't truly see it reflected until you commit to it with balance = withdraw()
. There's a good advantage to doing it this way, which is making sure that no exceptions occur and that if withdraw or deposit completely finished at 100% , then you can commit the changes.
I decided to go a bit further into your code, since you seem to have a whole lot of castings of ints , floats and while loops.
Here's an example of how it could be approached, in case it helps to give anyone more ideas: (remember, there's no single path with code, we all code differently)
f""
string format.So now the code.
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.")
Let's go through it bit by bit.
The decorator is this.:
def exit_on_input_cast_error(func):
def wrapper(arg):
try:
return func(arg)
except ValueError as ex:
print("Exiting, bye.")
exit()
return wrapper
That's just the syntax for a decorator. The important part is the return func(arg) . That's the function that will get caught. So this decorator is merely in charge of catching a ValueError exception, which can be thrown when you try to cast something like a int('a')
. This decorator is meant to prevent a user trying to withdraw or deposit strings into the atm machine. Since it's code that you will use for both input of withdrawing or depositing, I have placed it as a decorator for ease of call (hello DRY principle).
Next up we have the class constructor . I hope you are familiar with classes, if you are not, there's a lot of links and documentation you can look up so you understand the difference between a class and a method like you had originally. The biggest advantage in this case is that you can have multiple atm's with different amount of cash in each. Or you could instantiate an ATM class, and give it configuration like language, or coin type. Stuff like that.
class ATM():
"""A simple atm machine"""
def __init__(self, balance):
self.cash_available = balance
That's such normal syntax for defining the class. The """A simple atm machine""" is the docstring so that when you call the classes .__doc__ you would get that in return.
Now to the good stuff.
@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
This method is meant to handle getting the input of the user. See how it's decorated with @exit_on_input_cast_error ? That means that if the user puts in 'a' , then the program exits. That's because the int(...)
cast will throw that ValueError exception, that the decorator catches. The method does the following in pseudocode:
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.
That's basically what this method does. It keeps asking the user to enter a valid input until either the user does so, or they exit by entering "N". And why do they exit when they enter "N". Because "N" is not an int , so when the cast occurs in this line:
withdrawl = int(input("Enter the amount you want to withdraw (Press N to exit): AED "))
A ValueError will be thrown by int() , that Exception is then caught by the handy decorator @exit_on_input_cast_error
, which then prints "Bye" and exits for you. Cool right?
Next up is the actual withdraw method you had . The difference now is there is only one loop that continues to ask the user if he wants to keep withdrawing again once the action has finished. It's up to the user to either exit or withdraw again.
@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()
In pseudocode:
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.
That's essentially what the method does. And it uses to new methods that are for printing message.
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.")
These methods can be called and pass in custom parts of the message, like print_balance . They show the private class variable of the ATM class. In the withdraw method I have to point out that you can withdraw up to the point of reaching 0. The machine will let you try to keep withdrawing but it won't let you since there's 0 cash in it.
And last, the deposit method.
@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()
As you can see, very simple and follows the same principle. Here's how you would call the actual methods:
atm_a = ATM(600)
atm_a.withdraw()
Here's an output of the code:
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.
If you want to withdraw and deposit:
atm_a = ATM(600)
atm_a.withdraw()
atm_a.deposit()
Here's output of the code:
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.
Notice how you can only deposit once and then it exists. That's because I didn't implement that, since I already did that for withdraw . Anyone can just replicate it in the deposit if they want.
I hope this wasn't too much and that I managed to explain it. There's loads of things than can be added to this:
I agree with @Chetan Ranpariya's suggestion, you haven't change your balance
variable in your code for both function. You can change your balance
variable using the expression balance += <increase amount>
, balance -= <decrease amount>
or balance = balance + <increase amount>
, etc.
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):
print("Amount left in your account: AED" + str(balance - withdraw))
return (balance - withdraw)
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):
print("Amount left in your account: AED" + str(balance + deposit))
return (balance + deposit)
counter = counter + 1
balance = withdraw()
balance = deposit()
You are not changing the balance
variable, you are only returning the value with the added or reduced deposit
or withdraw
.
Try changing your code so that it saves the new balance
before returning it. So instead of:
print("Amount left in your account: AED" + str(balance - withdraw))
return (balance - withdraw)
Try:
balance = (balance - withdraw)
print("Amount left in your account: AED" + str(balance))
return balance
Then do the same with the deposit
function.
Your new code:
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):
balance = (balance - withdraw)
print("Amount left in your account: AED" + str(balance))
return 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):
balance = (balance + deposit)
print("Amount left in your account: AED" + str(balance))
return balance
counter = counter + 1
withdraw()
deposit()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.