【问题标题】:Incorrect checking of fields in list using a for loop使用 for 循环检查列表中的字段不正确
【发布时间】:2017-09-09 11:48:49
【问题描述】:

如果银行详细信息(用户和相应号码)匹配,我有以下代码试图将文件内容读入列表(此位有效),然后显示接受消息。

例如如果输入用户名:customer1 和 account_number:1 >> 文件中每个客户和帐号的访问权限被授予等等。

文件详情

customer1,1
customer2,2
customer3,3
customer4,4
customer5,5

代码

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 string
         split_line=line.split(",")
         for field in split_line:
            bankdetails.append(field)

   accessgranted=False
   while accessgranted==False:
       username=input("username:")
       password=input("account no:")

       for i in bankdetails:
          if username==bankdetails[i] and password==bankdetails[i+1]:
             accessgranted=True
             break
          else:
            accessgranted=False


       if accessgranted==True:
         print("Access Granted")
       else:
         print("Sorry, wrong credentials")

错误

 if username==bankdetails[i] and password==bankdetails[i+1]:
TypeError: list indices must be integers, not str

为了回答和教学/学习目的,我想要以下内容

  1. 使用现有提供的代码进行更正,并清楚地解释错误

  2. 关于以最有效的方法实现相同目标的替代方法的建议

【问题讨论】:

  • 错误是for循环中的i不是数字它是bankdetails的迭代器。尝试打印(i),你会看到

标签: python loops for-loop


【解决方案1】:

for i in bankdetails: 表示i 将成为bankdetails 中的每个元素,而不是它将成为元素的位置。如果你想让它成为位置,你必须做for i in len(bankdetails),因为len()是获取数据结构长度的函数。但是,由于您每次需要两个字段,我建议您使用 while 结构,如下所示:

total = len(bankdetails) - 1
i = 0
while i < total:
    if username==bankdetails[i] and password==bankdetails[i+1]:
        accessgranted=True
        break
    else:
        accessgranted=False
    i += 2

但是,如果您的列表中有很多条目,则遍历所有条目可能会花费大量时间。为了避免这种情况,使用字典是最好的选择:检查一个项目是否在其中要快得多,而且您不需要迭代来查找与其关联的值。

如果您不知道字典是如何工作的,它有点像一个列表,只是它们没有排序,而且您查找项目的方式是检查与键关联的值。让我们更清楚。在您的文件中,您有:

customer1,1
customer2,2
customer3,3
customer4,4
customer5,5

将它们添加到字典中的方法是:

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 string
         split_line=line.split(",")
         username = split_line[0]
         password = split_line[1]
         bankdetails[username] = password

这样,bankdetails 将包含{'customer1': '1', 'customer2': '2', ... }

而且,要查找用户及其密码,您必须这样做:

username=input("username:")
password=input("account no:")
if username in bankdetails:
    if bankdetails[username]==password:
       accessgranted=True
       break
    else:
        accessgranted=False

这将完全符合您的要求,但如果您有很多条目,则速度会更快。

【讨论】:

  • 将引发超出范围
  • 为什么 for i in len(bankdetails): print(bankdetails[i]) 不起作用?
  • 你能留下你的答案吗,我会检查,但也不要使用while循环。我想知道遍历列表的最佳方法(使用 for)。
  • @MissComputing,它会的。 bankdetails[i+1] 不起作用,因为 i + 1 将是 == len(bankdetails)
  • @Vadym - 不幸的是它没有,错误:for i in len(bankdetails): TypeError: 'int' object is not iterable
【解决方案2】:
def strip_split_read_from_file():
   bankdetails=[]
   with open("files.txt","r") as f:
      for line in f:
         line=line.rstrip()
         split_line=line.split(",")
         for field in split_line:
            bankdetails.append(field)

   accessgranted=False

   i = 0                               #1
   while accessgranted==False:

      username=input("username:")
      password=input("account no:")
      if username==bankdetails[i] and password==bankdetails[i+1]:
         accessgranted=True
         print("Access Granted")      #2
         break
      else:
         accessgranted=False
         print("Sorry, wrong credentials")     #3
      i += 2

1) 将启动文件中包含的数据的总长度

2) 如果用户名和密码正确,则在 break 之前打印“Access Granted”,否则将不会打印,因为在 break 后执行将移出循环

3) 如果数据不匹配,则打印错误的凭据并移至下一次迭代并再给一次机会

【讨论】:

    【解决方案3】:

    我会建议你下面的代码:

    import csv
    with open('bankdetails.txt', 'r') as file:
         reader = csv.reader(file)
         bankdetails = [row for row in reader]
    

    这将为您提供客户列表:

    [['customer1', '1'], ['customer2', '2'], ['customer3', '3'], ['customer4', '4'], ['customer5', '5']]
    

    现在,您可以更轻松地进行迭代:

    for customer in bankdetails:
        customer[0] would be your customer
        customer[1] would be your digit
    

    【讨论】:

      【解决方案4】:

      类似的东西(未经测试):

      def strip_split_read_from_file():
          bankdetails=[]
          with open("bankdetails.txt","r") as f:
              for line in f:
                  line = line.rstrip() 
                  pair = line.split(",")                          # 1 
                  assert(len(pair) == 2)                          # 2
                  bankdetails.append(pair)                        # 3
      
          accessgranted=False
          while accessgranted==False:
              username=input("username:")
              password=input("account no:")
      
              for pair in bankdetails:                            # 4
                  if username==pair[0] and password==pair[1]:     # 5
                      accessgranted=True
                      break
                  else:
                      accessgranted=False
      
      
              if accessgranted==True:
                  print("Access Granted")
              else:
                  print("Sorry, wrong credentials")
      

      注意事项:

      标记为 1-3 的行略微更改了存储(用户名、帐号)对的布局。您现在有两个维度,而不是存储为“平面”列表,其中索引 0,2,4,6,... 代表用户名,1,3,5,7,... 代表帐号。现在,bankdetails 是一个 2 元素元组的列表,其中第一个元素是用户名,第二个元素是帐号。这与您的文件布局非常相似。

      所以之前,您的列表看起来像:

      [username1, account1, username2, account2, username3, ...]
      

      现在看起来像:

      [
          (username1, account1),
          (username2, account2),
          (username3, account3),
          ...
      ]
      

      第 2 行只是对数据执行(非常基本的)完整性检查。

      第 4 行只是将循环变量重命名为 pair,以便更好地表示将分配给该变量的内容,即 bankdetails 条目——一对。 (i 通常保留给最小范围的整数循环变量)

      第 5 行使用 pair 并访问该对的各个元素 -- pair[0] 获取第一个,用户名,pair[1] 获取第二个/最后一个,帐号。

      这就是改变的一切。最终,您可能会考虑创建一个 Account 类,您可以为每个帐户实例化该类,并具有 usernameaccount_number 成员属性。您也可以将命名元组用于类似目的。

      此外,您可以稍微清理一下程序的流程,可能类似于(同样,未经测试):

      def strip_split_read_from_file():
          bankdetails=[]
          with open("bankdetails.txt","r") as f:
              for line in f:
                  line = line.rstrip() 
                  pair = line.split(",")                          # 1 
                  assert(len(pair) == 2)                          # 2
                  bankdetails.append(pair)                        # 3
      
          return bankdetails
      
      def evaluate_login(bankdetails, username, password):
          for pair in bankdetails:                                # 4
              if username==pair[0] and password==pair[1]:         # 5
                  return True
      
          return False
      
      
      # Read file containing account info
      bankdetails = strip_split_read_from_file()
      
      # Prompt user for login
      username=input("username:  ")
      password=input("account no: ")
      
      # Test user input
      accessgranted = evaluate_login(bankdetails, username, password):
      
      # Show login result
      if accessgranted==True:
          print("Access Granted")
      else:
          print("Sorry, wrong credentials")
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-11
        • 2017-09-06
        • 1970-01-01
        • 1970-01-01
        • 2017-04-05
        相关资源
        最近更新 更多