I have the following code that seeks to read the file contents into a list (this bit works) and then display a message of acceptance, IF the bank details (user and corresponding number) matches.
e.g. if username: customer1 and account_number:1 is entered >> Access Granted and so on for each customer and account number in the file.
File details
customer1,1
customer2,2
customer3,3
customer4,4
customer5,5
Code
def strip_split_read_from_file():bankdetails=[]with open("bankdetails.txt","r") as f:for line in f:line=line.rstrip() #r strip removes the new line character from the right side of the stringsplit_line=line.split(",")for field in split_line:bankdetails.append(field)accessgranted=Falsewhile accessgranted==False:username=input("username:")password=input("account no:")for i in bankdetails:if username==bankdetails[i] and password==bankdetails[i+1]:accessgranted=Truebreakelse:accessgranted=Falseif accessgranted==True:print("Access Granted")else:print("Sorry, wrong credentials")
Error
if username==bankdetails[i] and password==bankdetails[i+1]:
TypeError: list indices must be integers, not str
For an answer, and teaching/learning purposes I would like the following
Correction with clear explanation of the error using the existing, provided code
Suggestions as to alternative ways to achieve the same objective in the most efficient method possible
for i in bankdetails:
means that i
will become every element in bankdetails, not that it will become the position of the element. If you want it to become the position, you must do for i in len(bankdetails)
, because len()
is the function to get the length of a data structure. However, since you take two fields every time, I'd recommend to do it with a while structure, like this:
total = len(bankdetails) - 1
i = 0
while i < total:if username==bankdetails[i] and password==bankdetails[i+1]:accessgranted=Truebreakelse:accessgranted=Falsei += 2
However, if you have lots of entries in your list, iterating over all of them can take a lot of time. To avoid this, using a dictionary is the best option: checking if an item is in it is a lot faster, and you don't need to iterate to find the value associated with it.
If you don't know how dictionaries work, it kinda works like a list, except they're not ordered, and the way you look for an item is checking the value associated to a key. Let's be more clear. In your file, you have:
customer1,1
customer2,2
customer3,3
customer4,4
customer5,5
The way to add them in a dictionary would be:
bankdetails={} #Notice that they're initialized as {}with open("bankdetails.txt","r") as f:for line in f:line=line.rstrip() #r strip removes the new line character from the right side of the stringsplit_line=line.split(",")username = split_line[0]password = split_line[1]bankdetails[username] = password
This way, bankdetails will contain {'customer1': '1', 'customer2': '2', ... }
And, to look for the user and its password, you'd have to do this:
username=input("username:")
password=input("account no:")
if username in bankdetails:if bankdetails[username]==password:accessgranted=Truebreakelse:accessgranted=False
This will do exactly what you wanted, but much faster if you had lots of entries.