引用列表索引来枚举值

Reference list index to enumerate value

我有一个程序可以在 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()

问题是选择零将选择零索引,而不是 'search any'。如何使列表索引与枚举值匹配?

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

我什至不确定是否需要将字典转换为列表,但我读到枚举必须工作,所以我就这么做了。

看来您的代码中有一个小错误!

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

上一行包含0。0 >= 0 == True因此

elif senderNum == 0:

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

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

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

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

else:
    print('Incorrect value')
    continue

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

对于您输入非数字时发生的崩溃,因为您在将输入转换为 int 后有 try。所以你必须在 int(input("Choose a sender (zero for any): "))

之前尝试

我的建议是选择负数发送给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 作为 send any I 那么你必须执行以下操作:

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

解决您关于枚举和 dictionary/list 的最后一个问题。 字典没有排序,所以你不能用索引枚举它。所以有必要做一个转换成列表。另一种不将其转换为列表的使用方式是使用字典键作为输入而不是索引号。

The issue is that choosing zero will choose the zero index, instead of 'search any'. How do I make the list index match the enumerate values?

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

Also, entering a non-number or blank input crashes the program, so I'm not certain what exception covers that, I thought it fell under 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
>>> 

I'm not really sure if I even need to turn the dictionary into a list, but I had read that it was necessary for enumerate to work so I just went with it.

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

这里正确的解决方案是将你的字典变成一个 (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

感谢所有有用的回复!

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

listSender = list(senderDict.values())
listSender.insert(0, "Search Any")

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