【问题标题】:Reference list index to enumerate value引用列表索引来枚举值
【发布时间】:2020-04-03 09:40:09
【问题描述】:

我有一个程序可以检查 Outlook 收件箱中是否有来自字典中特定发件人的附件。 Python - Outlook search emails within specific range only

该程序运行良好,现在我正在尝试扩展它,让用户能够从字典中选择特定发件人,以便只搜索他们的电子邮件。这段代码在之前的程序中。

我的字典是senderDict = {sender@address.com : Sender Name}

为了把它变成一个可供选择的值的菜单,我使用了枚举:

listSender = list(senderDict.values())

for count, item in enumerate(listSender,1):
    print(count, item)

print("There are", len(listSender), "items.")

while True:
    senderNum = int(input("Choose a sender (zero for any): "))        
    try:
        if senderNum <= len(listSender) and senderNum >= 0:
            #senderNum = int(input("Choose a sender (zero for any): "))
            print("you chose", listSender[senderNum])
            break

        elif senderNum == 0:
            print("Searching for any sender")
            break

        elif senderNum < 0:
            print("Cannot choose a negative number.")
            continue

    except ValueError: #Not int
        print("You did not enter a valid number (ValueError)")
        input()

    except IndexError: #outside range
        print("You did not enter a valid number (IndexError)")
        input()

问题是选择零将选择零索引,而不是“搜索任何”。如何使列表索引与枚举值匹配?

另外,输入非数字或空白输入会使程序崩溃,所以我不确定是什么异常,我认为它属于 ValueError。

我不确定是否需要将字典转换为列表,但我已经读过 enumerate 需要它才能工作,所以我就照做了。

【问题讨论】:

  • @shyamzzp “which” 在这种情况下是正确的。请不要根据风格偏好进行虚假更改。

标签: python python-3.x list dictionary enumerate


【解决方案1】:

您的代码中似乎有一个小错误!

if senderNum <= len(listSender) and senderNum >= 0:

上面的行包括0。因此0 &gt;= 0 == True

elif senderNum == 0:

永远不会到达,因为它已经在前面的 if 语句中到达。我相信你想做的是

if senderNum <= len(listSender) and senderNum > 0:

这种方式,当所选择的数量为0时,上述行将是假的,并且您的代码将到达ELIF行。如果您需要它来匹配列表中的索引,因为您将枚举设置为从 1 开始,您可以手动从用户选择的值 count - 1 中减去 1。

为了捕获不正确的值,您可以添加一个 else 语句:

else:
    print('Incorrect value')
    continue

【讨论】:

    【解决方案2】:

    问题是选择零将选择零索引,而不是“搜索任何”。如何使列表索引与枚举值匹配?

    首先确定测试的顺序,然后从用户的输入中减去 1。

    另外,输入非数字或空白输入会使程序崩溃,所以我不确定是什么异常,我认为它属于 ValueError。

    int(something) 可以引发 TypeError(如果 type(something) 不是可以解释为数值的东西)或 ValueError 如果类型正常但不是值。

    input() (raw_input() in py2)always returns a string so you cannot have aTypeErroreher andValueError` 确实是你想要捕捉的——但你必须把你的 try/except 块放在正确的位置。目前您有:

    senderNum = int(input("Choose a sender (zero for any): "))        
    try:
      # use senderNum here
    except ValueError:
      # ...
    

    但是ValueError 是由int(...) 提出的,所以它确实不会被抓住。你想要:

    try:
       senderNum = int(input("Choose a sender (zero for any): "))        
    except ValueError:
       print("not a valid value")
       continue
    
    # ok, now `senderNum` is an integer
    

    此外,由于您测试 senderNum 在边界内,因此您不应该有任何 IndexError。好吧,实际上,如果测试正确,您就不会 - 您应该测试 senderNum 是否严格小于 len(listSender) - 请记住列表是从零开始的,因此列表的最后一个索引是len(lst) - 1:

    >>> lst = list("abc")
    >>> len(lst)
    3
    >>> 3 <= len(lst)
    True
    >>> lst[3]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    IndexError: list index out of range
    >>> 3 < len(lst)
    False
    >>> 
    

    我不确定是否需要将字典转换为列表,但我已经读过 enumerate 需要它才能工作,所以我就照做了。

    enumerate() 适用于任何可迭代对象。 dict 是可迭代的,因此您可以直接将 senderDict 传递给 enumerate - 但是您将拥有密钥,而不是名称。或者您可以直接传递senderDict.values(),但接下来您将遇到另一个问题,即如何从名称中取回电子邮件。

    此处正确的解决方案是将您的 dict 转换为 (key, value) 元组的列表 - 就像 list(senderDict.items()) 一样简单,因此您可以从选择的列表索引中获取名称和电子邮件。

    更正的代码:

    senders = list(senderDict.items())
    
    # this won't change during execution so let's 
    # stop recomputing it each time
    
    nb_senders = len(senders)
    
    for index, (email, name) in enumerate(senders, 1):
        print("{}: {} ({})".format(index, name, email)
    
    
    print("There are {} items.".format(nb_senders))
    
    
    while True:
        # get the raw input
        senderNum = input("Choose a sender (zero for any): ")        
    
        # now validate it
        try:
            senderNum = int(senderNum)
            if senderNum < 0:
                raise ValueError("should not be negative")
            if senderNum > nb_senders:
                raise ValueError("should be lesser than {}".format(nb_senders))
    
        except ValueError as e:
            print("'{}' is not valid choice: {}".format(senderNum,  e))
            continue
    
        # ok, done           
        if senderNum == 0:
            print("Searching for any sender")
            break
    
        print("you chose {} ({})".format(*listSender[senderNum]))
        break
    

    【讨论】:

      【解决方案3】:

      您的问题是如何列出与枚举值匹配的索引。这很容易,您只需从用户提供的输入中减去 1。问题出在您的 if 子句 senderNum &gt;= 0 中,如果您的用户输入 0,这将是真的,所以 elif senderNum == 0 永远不会是真的

      当您输入一个非数字时发生崩溃,因为您在将条目转换为 int 后有 try。所以你必须尝试int(input("Choose a sender (zero for any): "))

      我的建议是选择负数发送给任何人。

      所以我的建议如下:

      listSender = list(senderDict.values())
      
      for count, item in enumerate(listSender):
              print(count, item)
      
      print("There are", len(listSender), "items.")
      
      while True:
          try:  # have to be before the int(input(...)) to catch the exception
              senderNum = int(input("Choose a sender (-1 for any): "))        
      
              if senderNum < len(listSender) and senderNum >= 0: # len(listSender) is not allowed because the index starts at 0 and the last entry is len(listSender) -1                    
                  print("you chose", listSender[senderNum])
                  break
      
              elif senderNum < 0:
                  print("Search for any sender")
                  break
      
          except ValueError: #Not int
              print("You did not enter a valid number (ValueError)")
              input()
      
          except IndexError: #outside range
              print("You did not enter a valid number (IndexError)")
              input()
      

      如果你真的想使用 0 作为发送任何我,那么你必须执行以下操作:

      listSender = list(senderDict.values())
      
      for count, item in enumerate(listSender,1):
              print(count, item) 
      
      print("There are", len(listSender), "items.")
      
      while True:
          try:
              senderNum = int(input("Choose a sender (zero for any): "))
              if senderNum <= len(listSender) and senderNum > 0: # if senderNum is zero then send for any so senderNum >= 0 has to be changed to senderNum > 0
                  print("you chose", listSender[senderNum-1]) # because index starts with 0 you have to subtract 1 from the input
                  break
      
              elif senderNum == 0:
                  print("Searching for any sender")
                  break
      
              elif senderNum < 0:
                  print("Cannot choose a negative number.")
                  continue
      
          except ValueError: #Not int
              print("You did not enter a valid number (ValueError)")
              input()
      
          except IndexError: #outside range
              print("You did not enter a valid number (IndexError)")
              input()
      

      解决您关于枚举和字典/列表的最后一个问题。 字典没有排序,这就是为什么你不能用索引枚举它的原因。所以有必要将其转换为列表。另一种在不将其转换为列表的情况下使用它的方法是使用字典键而不是索引号作为输入。

      【讨论】:

        【解决方案4】:

        感谢所有有用的回复!

        我决定在将字典转换为列表后为“搜索任意”插入一个列表选项,而不是尝试更改输入的值,然后让枚举从零开始。这样我就不必做任何加法或减法,索引值仍然与输入匹配。

        listSender = list(senderDict.values())
        listSender.insert(0, "Search Any")
        
        for count, item in enumerate(listSender):
            print(count, item)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-13
          • 2022-01-20
          • 2016-06-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多