Bank ATM Program login - python

I want to make this program that acts as a bank, how do I make sure the correct ID number must be entered with the correct pin and have it depending on the id you entered print hello then their name and prompt how much money they have in the bank.
attempts = 0
store_id = [1057, 2736, 4659, 5691, 1234, 4321]
store_name = ["Jeremy Clarkson", "Suzanne Perry", "Vicki Butler-Henderson", "Jason Plato"]
store_balance = [172.16, 15.62, 23.91, 62.17, 131.90, 231.58]
store_pin = [1057, 2736, 4659, 5691]
start = int(input("Are you a member of the Northern Frock Bank?\n1. Yes\n2. No\n"))
if start == 1:
idguess = ""
pinguess = ""
while (idguess not in store_id) or (pinguess not in store_pin):
idguess = int(input("ID Number: "))
pinguess = int(input("PIN Number: "))
if (idguess not in store_id) or (pinguess not in store_pin):
print("Invalid Login")
attempts = attempts + 1
if attempts == 3:
print("This ATM has been blocked for too many failed attempts.")
break
elif start == 2:
name = str(input("What is your full name?: "))
pin = str(input("Please choose a 4 digit pin number for your bank account: "))
digits = len(pin)
balance = 100
while digits != 4:
print("That Pin is Invalid")
pin = str(input("Please choose a 4 digit pin number for your bank account: "))
digits = len(pin)
store_name.append(name)
store_pin.append(pin)

I'm very impressed by how much you've elaborated on your program. Here's how I would view your solution.
So to create a login simulation, I would instead use a dictionary. That way you can assign an ID to a PIN. For example:
credentials = {
"403703": "121",
"3900": "333",
"39022": "900"
}
Where your ID is on the left side of the colon and the PIN is on the right. You would also have to assign the ID to a name that belongs to that ID using, you guessed it, a dictionary!
bankIDs = {
"403703": "Anna",
"3900": "Jacob",
"39022": "Kendrick"
}
Now that you've done that, you can create your virtual login system using if/else control flow. I've made my code like this:
attempts = 0
try:
while attempts < 3:
id_num = raw_input("Enter your ID: ")
PIN = raw_input("Password: ")
if (id_num in credentials) and (PIN == credentials[id_num]):
print "login success."
login(id_num)
else:
print "Login fail. try again."
attempts += 1
if attempts == 3:
print "You have reached the maximum amount of tries."
except KeyboardInterrupt:
print "Now closing. Goodbye!"
Note the try and except block is really optional. You could use the break operator like you did in your code if you wanted to, instead. I just like to put a little customization in there (Remember to break out of your program is CTRL-C).
Finally, Python has a way of making life easier for people by using functions. Notice I used one where I put login(id_num). Above this while loop you'll want to define your login so that you can display a greeting message for that particular person. Here's what I did:
def login(loginid):
print "Hello, %s!" % bankIDs[loginid]
Simple use of string formatting. And there you have it. The same can be done with displaying that person's balance. Just make the dictionary for it, then print the code in your login definition.
The rest of the code is good as it is. Just make sure you've indented properly your while-loop inside the elif on the bottom of your code, and your last 2 lines as well.
Hope I helped. Cheers!

Related

why does this python while loop not work in the program?

I'm trying to run the program in the following article:
https://blockgeeks.com/guides/python-blockchain-2/
I've copied all of the code into my Spyder IDE. When i run it there's a while loop which starts up asking the user to choose a number from the list of options it prints.
After selecting a number the program should perform the requested action. When i select it though it just loops back to the start of the while loop.
It appears to be ignoring the rest of the code in the while loop (the if statement part).
Confusingly if i take the parts of the code from the program which are used in the while loop and run them separately they work i.e if i run the below code and select the number 1 for my choice it will run the code in the if statement.
Why would the if statement run here but not in the main program?
#function 1:
def get_user_choice():
user_input = input("enter a number: ")
return user_input
#function 2:
def get_transaction_value():
tx_recipient = input('Enter the recipient of the transaction: ')
tx_amount = float(input('Enter your transaction amount '))
return tx_recipient, tx_amount
while True:
print("Choose an option")
print('Choose 1 for adding a new transaction')
print('Choose 2 for mining a new block')
print('Choose 3 for printing the blockchain')
print('Choose anything else if you want to quit')
user_choice = get_user_choice()
if user_choice == '1':
tx_data = get_transaction_value()
print(tx_data)
Update:
Sorry i realise i may not have been very clear what the problem is.
The above code is part of the code from the entire program and runs as expected in isolation from the main program.
The below code is the entire program from the article in the link. It includes all of the code in the program. If i run this main program the while loop doesn't use the if statement. It appears to just be breaking straight out of the loop after i select 1, 2 or 3 (any other number should break out of the loop anyway).
Here's a link for a screen shot showing what the console looks like after i have selected the number 1 for the option.
https://ibb.co/RNy2r0m
# Section 1
import hashlib
import json
reward = 10.0
genesis_block = {
'previous_hash': '',
'index': 0,
'transaction': [],
'nonce': 23
}
blockchain = [genesis_block]
open_transactions = []
owner = 'Blockgeeks'
def hash_block(block):
return hashlib.sha256(json.dumps(block).encode()).hexdigest()
# Section 2
def valid_proof(transactions, last_hash, nonce):
guess = (str(transactions) + str(last_hash) + str(nonce)).encode()
guess_hash = hashlib.sha256(guess).hexdigest()
print(guess_hash)
return guess_hash[0:2] == '00'
def pow():
last_block = blockchain[-1]
last_hash = hash_block(last_block)
nonce = 0
while not valid_proof(open_transactions, last_hash, nonce):
nonce += 1
return nonce
# Section 3
def get_last_value():
""" extracting the last element of the blockchain list """
return(blockchain[-1])
def add_value(recipient, sender=owner, amount=1.0):
transaction = {'sender': sender,
'recipient': recipient,
'amount': amount}
open_transactions.append(transaction)
# Section 4
def mine_block():
last_block = blockchain[-1]
hashed_block = hash_block(last_block)
nonce = pow()
reward_transaction = {
'sender': 'MINING',
'recipient': owner,
'amount': reward
}
open_transactions.append(reward_transaction)
block = {
'previous_hash': hashed_block,
'index': len(blockchain),
'transaction': open_transactions,
'nonce': nonce
}
blockchain.append(block)
# Section 5
def get_transaction_value():
tx_recipient = input('Enter the recipient of the transaction: ')
tx_amount = float(input('Enter your transaction amount '))
return tx_recipient, tx_amount
def get_user_choice():
user_input = input("Please give your choice here: ")
return user_input
# Section 6
def print_block():
for block in blockchain:
print("Here is your block")
print(block)
# Section 7
while True:
print("Choose an option")
print('Choose 1 for adding a new transaction')
print('Choose 2 for mining a new block')
print('Choose 3 for printing the blockchain')
print('Choose anything else if you want to quit')
user_choice = get_user_choice()
if user_choice == 1:
tx_data = get_transaction_value()
recipient, amount = tx_data
add_value(recipient, amount=amount)
print(open_transactions)
elif user_choice == 2:
mine_block()
elif user_choice == 3:
print_block()
else:
break
[1]: https://i.stack.imgur.com/FIrn7.png
When comparing values, Python takes a stronger route regarding data types than some other languages. That means no string in Python will equal a number.
Or in other terms "1" == 1 will be False.
That means you have to consider that in Python 3 you will receive a string from input() (not necessarily so in Python 2).
You can either compare this directly to another string:
user_choice = input()
if user_choice == "1":
print("You chose item 1")
Or you can convert it into a number first and compare it to a number:
user_choice = int(input())
if user_choice == 1:
print("You chose item 1")
Note that in the former case it might not be robust if the user enters extra spaces and in the latter case it will fail very loudly with an exception if the user doesn't enter an integer (or even nothing at all).
Both ways can be handled with extra code if necessary. In the former case, you can strip whitespace with user_input = input().strip() and in the latter case you can catch the exception with a try ... except ... block.
You have only handled the case for user_choice == '1'. If you enter anything other than 1, the program will return control to the beginning of the while loop.
I'll suggest you use a debugger to see what user_choice is before the if condition. If not, just use prints.
print("user_choice: {}, type: {}".format(user_choice, type(user_choice))

Python - Access and use specific object during runtime

I am working on a bank account program where the user logs in with a four digit number (pin).
I want to find a way to access a specific object with all its attributes at runtime after the right pin has been entered.
class Konto(object):
def __init__(self, account_holder, balance , pin):
self.account_holder = account_holder
self.balance = balance
self.pin = pin
I have three different objects defined in a list
kontoList = []
kontoList.append(Konto("Person1", 143541, 1223)),
kontoList.append(Konto("Person2", 6230, 1234)),
kontoList.append(Konto("Person3", 4578, 4321))
The last attribute is the Pin that is entered by the user. When the program checks the pin is '1234' for example it displays a menu where you can get the current balance, account holder etc. In this case it would be 6230 (balance) and Person2 (account holder). So here is some code:
pin = input("PIN: ")
for konto in kontoList:
if konto.pin == pin:
print("Valid PIN")
continue
else:
print("not valid")
break
while True:
print("1: Withdrawal \n"
"2: Deposit \n"
"3: Transfer \n"
"4: Current Balance \n"
"5: Account Holder \n"
"6: Quit \n")`
choice = input("Your Choice: ")
Is there any way to access the specific object during runtime and then go on to work with it? I've looked up getattr() but it does not seem useful in this situation.
You could simply create a list of pins, then check whether the pin you're checking is contained in that list:
kontoPinList = [konto.pin for konto in kontoList]
and then you would check whether your pin is in the kontoPinList with:
pin in kontoPinList
EDIT: If you want to keep working with the konto you do the following:
for konto in kontoList:
if konto.pin == pin:
#do something with the konto here
EDIT nr.2: If you wish to now call functions on the konto, such as account_holder(), you just do account_holder(konto) and that should work.
The reason my first response was to write a getPin() function is because while this will not solve your problem, it is a good idea to "protect" your variables by deciding how you want to return them. (it's more of a java thing than a python thing)
However, as you pointed out, it is a useless function if all you're interested in is simply returning konto.pin .
You could try something like this:
kontos_with_pin = filter((lambda k: k.pin == pin), kontoList)
if len(kontos_with_pin) == 1:
relevant_konto = kontos_with_pin[0]
# Do something with relevant_konto
else:
# handle case where there is no konto with that pin, or more than one, etc.

Checking if inputted strings are equal to strings in list?

I'm working on a project that involves building a simplified version of a calendar agent that asks the user for when they want to schedule an appointment and does it for them (if that slot is free). This is the code I have so far:
def find_index(val, seq):
for index in range(len(seq)):
place = seq[index]
if place == val:
return index
else:
return int("-1")
def find_val(val, seq):
for ele in seq:
if val == ele:
return True
else:
return False
def init_nested_list(size_outer, size_inner):
cal = []
for outer_index in range(size_outer):
nested_list = []
for inner_index in range(size_inner):
nested_list.append("-")
cal.append(nested_list)
return cal
def get_input(possible_vals, day_or_time_string):
count = 0
if day_or_time_string == "day":
answer = input("What day would you like your appointment? ")
else:
answer = input("What time would you like your appointment? ")
answer = answer.strip()
nested_list = find_val(answer, possible_vals)
while answer in possible_vals:
break
else:
count = count + 1
answer = input("Invalid entry. Please enter a valid day: ")
if count == 3:
print("This is getting silly - still not a valid entry")
answer = input("Please do try to enter a valid day: ")
count = 0
return answer
def book_slot(cal,days_labels, times_labels, day, time): **ignore this function, haven't finished it yet**
find_index(day, days_labels)
def start_scheduler(cal, days_labels, times_labels):
while True:
day = get_input(days_labels, "day")
time = get_input(times_labels, "time")
book_slot( cal, days_labels, times_labels, day, time)
print("--------------------------------- ")
res = input("Did you want to book more appointments (type n for no, any other key for yes)? ")
if res == "n":
break
days_labels= ["Monday","Tuesday","Wednesday","Thursday", "Friday"]
times_labels = ["9","10","11","12","1","2","3","4","5"]
calendar = init_nested_list(len(days_labels), len(times_labels))
print("Welcome to the acupuncture booking system. ")
start_scheduler(calendar, days_labels, times_labels)
This is what the complete output should look like so far:
Welcome to the acupuncture booking system.
What day would you like your appointment? saturday
Invalid entry. Please enter a valid day: Monday
What time would you like your appointment? 24
Invalid entry. Please enter a valid time: 9
---------------------------------
Did you want to book more appointments (type n for no, any other key for yes)?
However, it seems that no matter what I input when the function asks me for the date/time of the appointment, it doesn't check to see if the inputted strings are equivalent to any of the acceptable ones (in the lists days_labels and times labels). Instead it just accepts any second random input to be correct as shown:
Welcome to the acupuncture booking system.
What day would you like your appointment? s
Invalid entry. Please enter a valid day: z
What time would you like your appointment? d
Invalid entry. Please enter a valid day: f
---------------------------------
Did you want to book more appointments (type n for no, any other key for yes)?
What needs to be done in order to have the function check to see if the inputted strings correspond with any of the strings in the days_labels and times_labels lists in order for the user to "book" an appointment?
So you wont to create a function to check if any inputted string have been already used.
There reason your code isnt working correctly is because you tried to check wherethere your counter is up to 3, while it isnt any loop, and thus it only ascends to 1.
To re-arrange that to a correct way for example, you would do this:
while answer not in possible_values:
<your code here>
I didn't test this at all but it should be enough to guide you to fix your incrementing error.
def isValidDayInput(input):
accept = false
# your code here
return accept
def dayInput(count, maxAttempts):
waiting = true
while (waiting && count <= maxAttempts):
answer = promptForInput()
if (isValidDayInput(answer)): # accept returned true during validation
waiting = false # answer is valid so jump out loop
else(): # accept returned false during validation
count += 1
if (!waiting && count == maxAttempts):
print("Too many incorrect attempts. Exit")
else:
print("thank you")

I'm having issues looping through a tuple

I'm writing a program to simulate a bank scenario. It allows users (once they have logged in) to display their balance, withdraw and deposit money, and will eventually contain a transfer subroutine.
My problem is the login subroutine. I am having trouble getting my code to loop through both accounts in the tuple that saves them. I can log in to the first account and perform all the code's functions with that account but when I try to access the second account, I get the error message telling me that the account is not found. I am very certain that this is to do with the way I have written my loop but I cannot figure out how to fix it.
If someone could provide me with a solution that I can use to fix this error then I would be very grateful. If it is possible, could the solution also stick to the general format of my code and not be one where I have to create new functions and change the entire body of my LogOn function?
Here is the code:
accounts=[
["Luke",'00001','1234',1337],
["Louis",'00002','4321',420],
]
name = ""
x = []
def LogOn():
global name
global x
print ("Welcome to the Bank of Bailey")
accnum = raw_input("-please enter your account number-")
if len(accnum) != 5:
print("That number is not valid, please enter a valid number")
LogOn()
else:
for x in range(0,len(accounts)):
if accnum in accounts[x][1]:
name = accounts[x][0]
print ("Account found")
pin = raw_input("-please enter your pin-")
if pin in accounts[x]:
print ("Pin found")
MainMenu()
else:
print("Pin not found")
print("Please try again")
LogOn()
break
else:
print("Account not found")
print("Please try again")
LogOn()
The problem is:
if accnum in accounts[x][1]:
do something
else:
print("Account not found")
print("Please try again")
LogOn()
The else branch is called already for the first iteration (with x = 0)!
You should check after the while-loop if an account was found and otherwise print your error message.
Instead of recursing to LogOn() you could better use an outer (endless-)while-loop which calls LogOn(). In LogOn then just do a return in error case.
A few observations:
The else branch is called on the first iteration when x=0. You need to finish the for loop, then branch if the account has not been found.
if pin in accounts[x] is a security hole because it allows people to use their name or account number as their pin!
"if accnum in account[1]" should be "if accnum == account[1]"
Hope that helps!
accounts=[
["Luke",'00001','1234',1337],
["Louis",'00002','4321',420],
]
name = ""
x = []
def LogOn():
global name
global x
print ("Welcome to the Bank of Bailey")
accnum = raw_input("-please enter your account number-")
if len(accnum) != 5:
print("That number is not valid, please enter a valid number")
LogOn()
else:
found = False
for account in accounts:
if accnum == account[1]:
found = True
name = account[0]
print ("Account found")
pin = raw_input("-please enter your pin-")
if pin in account[2]:
print ("Pin found")
MainMenu()
else:
print("Pin not found")
print("Please try again")
LogOn()
break
if not found:
print("Account not found")
print("Please try again")
LogOn()
I like #TimSC's answer, but I'll add a few more observations:
LogOn is not a good function name; it should be log_on to match PEP8 naming conventions (LogOn suggests it is a class rather than a function).
You declare name and x as globals, then never use them. Globals are almost always a bad idea, and unused declarations just clutter your code.
As #CTX pointed out, you are using recursion (LogOn calling LogOn calling MainMenu calling LogOn etc) where iteration would make a lot more sense - you should back out on an error, not call again a level deeper.
Mixing input/output code and action code is usually a bad decision; it makes your code less flexible and reusable and often harder to debug as well. You should instead have an input/output function which calls an action function with the values it needs.
Giving separate error messages for bad account number, bad pin number is a security hole; it makes it much easier for would-be attackers to find valid account numbers to attack.
Looking things up in a list is relatively slow (O(n) ie time proportional to the number of items in the list). Use a dict instead (O(1) ie constant time - a quick hash calculation takes you right to the item you are looking for).
Here is a fancied-up version; may it give you things to think about:
import sys
# version compatibility shim
if sys.hexversion < 0x3000000:
inp = raw_input # Python 2.x
else:
inp = input # Python 3.x
class Account:
index = {}
__slots__ = ("accnum", "pin", "name", "balance")
#classmethod
def log_in(cls, accnum, pin):
key = (accnum, pin)
acc = Account.index.get(key, None)
if acc is None:
raise ValueError("No such login (bad account# or PIN)")
else:
return acc
def __init__(self, accnum, pin, name, balance):
# save values
self.accnum = accnum
self.pin = pin
self.name = name
self.balance = balance
# add self to account index
key = (accnum, pin)
Account.index[key] = self
# create accounts
Account('00001', '1234', "Luke", 1337)
Account('00002', '4321', "Louis", 420)
def main():
while True:
print("\nWelcome to the Bank of Bailey")
accnum = inp("Please enter your account number: ").strip()
pin = inp("Please enter your PIN: ").strip()
try:
acc = Account.log_in(accnum, pin)
print("\nYour account has a current balance of ${:0.2f}".format(acc.balance))
print("Thank you for banking with us!")
except ValueError as ve:
print(ve)
if __name__ == "__main__":
main()

Problems transferring information from one part of a function to another

While working on my program I have run into a problem where the information stored in Menu option 1 is not being transferred to Menu option 2. As you can see it is correctly stored when in menu one. When it returns to go to menu option 2 its like it never went to option 1.
update #1:
some suggestions I've had is to understand scope? from what I can tell the program is not passing the data along to its parent program even though I've typed out return in each of the definitions.
#Must be able to store at least 4 grades
#Each class can have up to 6 tests and 8 hw's
#Weighted 40%*testavg 40% hw average attendance is 20%
#User must be able to input a minimum grade warning
#after each test the your program must calculate the students average and issue warning if necessary
##Define the Modules##
import math
def menu (a): #2nd thing to happen
menuend = 'a'
while menuend not in 'e':
menuend = raw_input("Type anything other then 'e' to continue:\n")
print "What would you like to do ?"
menudo = 0
print "1 - Enter Courses\n2 - Select Course to Edit\n3 - Save File\n4 - Load File\n5 - Exit\n"
menudo = input("Enter Selection:")
if (menudo == 1):
menuchck = 0
menuchck = raw_input("\nYou have entered #1 (y/n)?:\n")
if menuchck in ["Yes","yes","y","Y"]:
x = m1()
else:
print "I'm sorry,",nam,",for the confusion, lets try again\n"
menu()
elif (menudo == 2):
menuchck1 = 0
menuchck1 = raw_input("\nYou have entered #2 (y/n)?:\n")
if menuchck1 in ["Yes","yes","y","Y"]:
x = m2()
else:
print "I'm sorry,",nam,",for the confusion, lets try again\n"
menu()
elif (menudo == 3):
print "Entered 3"
elif (menudo == 4):
print "Entered 4"
else:
print "Anything Else Entered"
def course(): #3rd thing to happen
b = {}
while True:
while True:
print "\n",name,", please enter your courses below ('e' to end):"
coursename = raw_input("Course Name:")
if (coursename == 'e'):
break
will = None
while will not in ('y','n'):
will = raw_input('Ok for this name : %s ? (y/n)' % coursename)
if will=='y':
b[coursename] = {}
print "\n",name,", current course load:\n",b
coursechck = None
while coursechck not in ('y','n'):
coursechck = raw_input("Are your courses correct (y/n)")
if coursechck =='y':
return b
else:
b = {}
print
##Menu Options##
def m1():
a = course()
return a
def m2():
print "Excellent",name,"lets see what courses your enrolled in\n"
print x
return x
###User Input Section###
name = raw_input("Enter Students Name:\n")
a = {}
menu(a)
raw_input("This is the end, my only friend the end")
In your if-elif blocks in the do==1 case, you write m1(), but for the last case, you write x=m1(). You should have the latter everywhere (by typing m1() you only run the function, but do not store the returned x anywhere).
By the way, you can avoid this if-elif confusion using if chck in ["Yes","yes","Y","y"]:

Categories