从函数中无形跳转到主菜单 - 任何人都可以发现错误吗?

时间:2017-09-02 07:00:24

标签: python function

我有以下代码,其中一个令人困惑的跳转回到quiz1()函数的登录函数中的第48行。代码似乎很好,无法找到错误的来源或原因,因为它没有理由回去!

可以在此处测试并找到包含文件的完整代码

https://repl.it/KdEI/2

测试数据:

username: admin
password: admin123

Press 1 to play
Press 1 to go to Quiz

>>ERROR (Jumps back to the main menu, and specifically to line 48 in the login function

注释

我假设错误位于登录代码中的某处。要给出答案,我想:

  1. 发现并解释了错误
  2. 关于更优雅的解决登录方式的评论(从文件中读取的用户名和密码)< - 目前设置“无效的用户名或密码”也不能正常工作。
  3. 登录功能代码:

    def login():
      print("===Login===")
      username=input("Enter username:")
      password=input("Enter password:")
      with open('userinfo.txt','r') as f:
        reader=csv.reader(f)
        username_correct=False
        password_correct=False
        while username_correct==False and password_correct==False:      
          for row in reader:
              for field in row:
                if field==username:
                  currentindex=row.index(field)
                  if row[currentindex+1]==password:
                    print("****You're in!*****")
                    username_correct=True
                    password_correct=True
                    print()
                    f.close()
                    mainmenu()
                  else:
                    break
    
          print("Wrong username or password, sorry!")
          welcomemenu()
    

    更新

    这似乎有效,通过从while循环中删除对主菜单的调用。但是,如果用户错误的话,代码需要重构优雅和输出“无效组合或用户详细信息”的最佳方式:

    def login():
      print("===Login===")
      passwordC=False
      usernameC=False
    
      while passwordC==False and usernameC==False:    
          username=input("Enter username:")
          password=input("Enter password:")
          with open('userinfo.txt','r') as f:
            reader=csv.reader(f)
    
            for row in reader:
              for field in row:          
               if field==username and row[1]==password:
                 passwordC=True
                 usernameC=True
    
    
      if passwordC==True and usernameC==True:
        print("**You're in**")
        mainmenu()
      else:
        print("Try again - wrong username and password")
        login()
    

4 个答案:

答案 0 :(得分:1)

在循环中执行mainmenu是您的错误。 尝试:

def login():
    print("===Login===")
    username=input("Enter username:")
    password=input("Enter password:")
    with open('userinfo.txt','r') as f:
        reader=csv.reader(f)
        username_correct=False
        password_correct=False
        for row in reader:
            for field in row:
                if field==username:
                    currentindex=row.index(field)
                    if row[currentindex+1]==password:
                        username_correct=True
                        password_correct=True
    if password_correct == False or username_correct == False:
        print("Wrong username or password, sorry!")
        welcomemenu()
    print("****You're in!*****")
    mainmenu()

由于程序未完成,您需要退出

def quiz1():
    print("===Quiz1===")
    print("Question 1:")
    exit()

答案 1 :(得分:0)

不需要usernameCpasswordC

def login():
  print("===Login===")

  while True:    
      username=input("Enter username:")
      password=input("Enter password:")
      with open('userinfo.txt','r') as f:
        reader=csv.reader(f)

        for row in reader:
          for field in row:          
           if field==username and row[1]==password:
               mainmenu()
               break
      print("Try again - wrong username and password")

这应该解决问题。

如果你想使用我在下面描述的pickle,函数定义将如下所示(更简单):

with open("userdata.pkl", "rb") as f:
    userdata = pickle.load(f)

def login():
  print("===Login===")
  while True:    
      username=input("Enter username:")
      password=input("Enter password:")

      if username in userdata:
          if userdata[username] == password:  # Checks the password.
               mainmenu()
               break
      print("Try again - wrong username and password")

此外,我想指出,即使出于学习目的,将密码存储在文本文件中也是一个坏主意。如果您不想使用数据库,请使用二进制文件来存储用户名和密码。使用如下例程:

import pickle

data = {"user1": "password1", "user2": "password2"}  # dictionary would be the data structure of the choice for this case.
with open("userdata.pkl", "wb") as f:
    pickle.dump(data, f)

稍后,您可以按如下方式检索字典:

with open("userdata.pkl", "rb") as f:
    userdata = pickle.load(f)

现在,print(userdata)会提供:{"user1": "password1", "user2": "password2"}

答案 2 :(得分:0)

我发现了我认为的错误。

  for row in reader:
      for field in row:
        if field==username:
          currentindex=row.index(field)
          if row[currentindex+1]==password:
            print("****You're in!*****")
            username_correct=True
            password_correct=True
            print()
            f.close()
            mainmenu()
          else:
            break

用户登录后关闭文件。然后你调用mainmenu函数。从主菜单函数返回后,您继续循环到文件的下一行...但您已经关闭该文件...因此错误。

试试看看它是否有效(不需要csv阅读器)

def login():
  print("===Login===")
  username=input("Enter username:")
  password=input("Enter password:")
  with open('userinfo.txt','r') as f:
    authenticated = False
    line = f.readline().strip()
    while authenticated ==False and line != "":
        values = line.split(",")
        if len(values) >= 2 and values[0] == username and values[1] == password:
            authenticated=True
        line = f.readline().strip()
    if authenticated:
        print("****You're in!*****")
        mainmenu()
    else:
        print("Wrong username or password, sorry!")
        welcomemenu()

答案 3 :(得分:0)

我不知道你是否已经解决了这个问题,但最初的问题是list.index没有按照你的想法做到 - 它没有给出当前项目的索引,而是搜索对于匹配的项目并给出该索引。所以,例如:

row = [1, 1, 1, 1, 1]
print(row[4], row.index(row[4]))

打印1 0,而不是1 4。您的userinfo文件包含两个包含“admin”的字段,因此您将获得两个与密码匹配的字段。

获取当前字段索引的最佳方法是使用enumerate

for currentindex, field in enumerate(row):

重写login()函数,使其更具可读性,我认为您打算执行以下操作:

def is_valid_user(username, password):
  with open('userinfo.txt','r') as f:
    for row in csv.reader(f):
      if row[0] == username and row[1] == password:
        return True
  return False

def login():
  print("===Login===")
  username=input("Enter username:")
  password=input("Enter password:")
  if is_valid_user(username, password):
    mainmenu()
  else:
    print("Wrong username or password, sorry!")
    welcomemenu()

从当前函数调用下一个函数的方式也存在问题。 例如,如果您反复输入错误的密码,您将获得以下函数调用链:

main -> welcomemenu -> login -> welcomemenu -> login -> welcomemenu ->
  login -> welcomemenu -> login -> welcomemenu -> login -> welcomemenu ->
  login -> welcomemenu -> login -> welcomemenu -> login -> welcomemenu etc

迟早,这种模式会给你带来麻烦。相反,尝试将函数调用安排为“扇出”,如下所示:

def welcomemenu():
  while True:
    print("""
      =========*WELCOME MENU*===========
      1. Register               
      2. Login
      3. Quit

      *You need to register and login for access to the game menu
      """)
    userselection=int(input("Enter Selection"))
    if userselection==1:
      register()
    elif userselection==2:
      if login():
        mainmenu()
        break
    elif userselection==3:
      break

def is_valid_user(username, password):
  with open('userinfo.txt','r') as f:
    for row in csv.reader(f):
      if row[0] == username and row[1] == password:
        return True
  return False

def login():
  print("===Login===")
  username=input("Enter username:")
  password=input("Enter password:")
  valid = is_valid_user(username, password)
  if not valid:
    print("Wrong username or password, sorry!")
  return valid

所以'错误的密码'序列现在会出现:

main -> welcomemenu -> login (back) -> login (back) -> login (back) etc