Python 从函数跳到主菜单的不可见跳转-有人能发现错误吗?

Python 从函数跳到主菜单的不可见跳转-有人能发现错误吗?,python,function,Python,Function,我有下面的代码,其中从quiz1()函数跳回到login函数的第48行,令人困惑。代码看起来很好,找不到错误的来源或原因,因为没有理由返回 可以在此处测试并找到文件的完整代码: 测试数据: 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

我有下面的代码,其中从quiz1()函数跳回到login函数的第48行,令人困惑。代码看起来很好,找不到错误的来源或原因,因为没有理由返回

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

测试数据:

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
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()
评论

我假设错误在登录代码中的某个地方。要奖励答案我想:

  • 发现并解释了错误

  • 关于解决登录(从文件读取用户名和密码)的更优雅方法的评论不需要
    usernameC
    passwordC

    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
    ,函数定义如下所示(简单得多):

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

    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)
    
    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()
    
    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
    
    稍后,您可以按如下方式检索词典:

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

    现在,
    print(userdata)
    会给出:
    {“user1”:“password1”,“user2”:“password2”}

    我发现了我认为是错误的地方

      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
    
    用户登录后,关闭该文件。然后调用主菜单功能。从主菜单函数返回后,继续for循环到文件的下一行。。。但是你已经关闭了那个文件。。。因此是错误的

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


    在循环中执行
    main菜单
    是您的错误。 尝试:

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

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

    我不知道你是否已经解决了这个问题,但最初的问题是list.index并不像你想象的那样-它不会给出当前项的索引,而是搜索匹配项并给出该索引。例如:

    row = [1, 1, 1, 1, 1]
    print(row[4], row.index(row[4]))
    
    打印
    10
    ,而不是
    14
    。您的userinfo文件包含两个包含“admin”的字段,因此您将获得两个与密码匹配的字段

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

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

    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)
    
    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()
    
    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
    
    从当前函数调用下一个函数的方式也有问题。e、 例如,如果反复输入错误的密码,则会得到以下函数调用链:

    main -> welcomemenu -> login -> welcomemenu -> login -> welcomemenu ->
      login -> welcomemenu -> login -> welcomemenu -> login -> welcomemenu ->
      login -> welcomemenu -> login -> welcomemenu -> login -> welcomemenu etc
    
    这种模式迟早会给你带来问题。相反,尝试安排对“扇出”的函数调用,如下所示:

    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)
    
    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()
    
    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)等

    我认为你应该使用数据库(如果这是一个轻型应用程序,可能是sqlite)来存储用户名和密码。我不想使用数据库。这是用于教学和学习的目的,需要解决,因为isIs现在已经修复了吗?这是一个有用的帖子,谢谢。如果你能分析代码中的奇怪错误,我可以接受你的答案。你也可以编辑你的答案,包括用户名和密码搜索。更新:这似乎可行…(在循环出现时),但如果组合错误,它仍然不会说“无效”:Sam Chats-谢谢,但与萨克森州的Rolf的答案类似,它似乎可行,但无法进一步测试。试试这个(它在登录功能中包含您的代码)…首先将用户名和密码弄错,然后继续将其弄错,并使用游戏和测验功能。您会注意到第二次它仍然错误地返回到登录函数!为什么?你还接到了whileloop中主菜单的呼叫,并清除了标志。我认为这并不理想?Saxony的repl.it/KdEI/4 Rolf解决方案似乎最接近,但当您第一次尝试时用户名和密码出错时,仍然不起作用。然后通过admin和admin123,您会注意到错误…它从quiz1函数返回,位于登录函数53中感谢您neh。如果您能够查看该链接,它将向您显示,即使删除f.close(),错误(跳回第48行)仍然存在。请参阅更新-从while循环中删除的主菜单调用,这会有所帮助。仍然需要修复。这是因为当你需要一个循环时,你有两个循环。。。不需要第二个循环。不必检查行(0到4)的每个字段,只需检查行[0]和行[1],我将添加更优雅的解决方案,看看是否有帮助。。。如果没有,请告诉我。谢谢neh-但我正在尝试修复现有的解决方案。这是Sam Chat的解决方案-请参阅上面的帖子以获取我的评论。它似乎可以工作,但如果你第一次把用户名和密码弄错了,它就不能工作。此外,他还接到了whileloop内主菜单的电话,并清除了旗帜。我不认为那是理想的。。。这是登录功能中与您的解决方案的链接。它似乎可以工作,但用以下方法测试它:首先将用户名和密码弄错,然后再次检查并转到测验函数=您将看到它再次返回到登录函数。。。!有什么想法吗?我明白你的意思,但问题仍然没有完全解决……exit()只是关闭整个程序并强制退出。我只想让它在命令提示下停止?您可以使用命令行上的
    -I
    (减号眼)选项在
    交互模式下运行脚本,但我看不到结果。顺便说一句,取消已授予的声誉积分并对现有问题增加进一步要求是不可取的。你当然可以接受另一个答案,如果它更适合你的问题。如果是这样,我鼓励你这样做。