Python 具有不同特定消息的相同异常

Python 具有不同特定消息的相同异常,python,error-handling,python-3.4,Python,Error Handling,Python 3.4,我试图编写一个代码来区分以下四种不同的错误 TypeError:第一个参数不是整数 TypeError:第二个参数不是字符串 ValueError:第一个参数的值不在1到13的范围内;或 ValueError:第二个参数的值不是集合{'s',h',c',d}中的字符串之一 但是,我只能使第一个错误生效,而不能使其他三个错误生效。我尝试了不同的方法使它工作,但仍然不能找出什么是错误的 class Card: # One object of class Card represents a playi

我试图编写一个代码来区分以下四种不同的错误

  • TypeError
    :第一个参数不是整数
  • TypeError
    :第二个参数不是字符串
  • ValueError
    :第一个参数的值不在
    1
    13
    的范围内;或
  • ValueError
    :第二个参数的值不是集合
    {'s',h',c',d}
    中的字符串之一
  • 但是,我只能使第一个错误生效,而不能使其他三个错误生效。我尝试了不同的方法使它工作,但仍然不能找出什么是错误的

    class Card: # One object of class Card represents a playing card
    
        rank = ['','Ace','Two','Three','Four','Five','Six','Seven','Eight','Nine','Ten','Jack','Queen','King']
        suit = {'d':'Diamonds', 'c':'Clubs', 'h':'Hearts', 's':'Spades'}
    
        def __init__(self, rank=2, suit=0): # Card constructor, executed every time a new Card object is created
            if type(rank) != int:
                raise TypeError()
            if type(suit) != str:
                raise TypeError()
            if rank != self.rank:
                raise ValueError()
            if suit != 'd' or 'c' or 'h' or 's':
                raise ValueError()
            self.rank = rank
            self.suit = suit
    
        def getRank(self): # Obtain the rank of the card
            return self.rank
    
        def getSuit(self): # Obtain the suit of the card
            return Card.suit[self.suit]
    
        def bjValue(self): # Obtain the Blackjack value of a card
            return min(self.rank, 10)
    
        def __str__(self): # Generate the name of a card in a string
            return "%s of %s" % (Card.rank[int(self.rank)], Card.suit[self.suit])
    
    if __name__ == "__main__": # Test the class Card above and will be skipped if it is imported into separate file to test
        try:
            c1 = Card(19,13)
        except TypeError:
            print ("The first parameter is not an integer")
        except TypeError:
               print ("The second parameter is not a string")
        except ValueError:
            print ("The value of first parameter is not in the range of 1 to 13")
        except ValueError:
            print ("The value of second parameter is not one of the strings in the set {'s','h','c','d'}")
    
        print(c1)
    

    我知道可能是因为我有相同的
    TypeError
    ValueError
    。因此,Python无法区分我点击的第二个
    TypeError
    c1=Card(13,13)
    与第一个
    TypeError
    不同。因此,当我有
    c1=Card(13,13)
    时,我只得到一条信息,即
    “第一个参数不是整数”
    ,您试图在完全错误的位置区分错误源。当错误从
    卡中消失时,无法知道抛出的原因,例如
    类型错误
    。对于每个错误类别(
    TypeError
    ValueError
    只会触发除
    之外的第一个

    try:
        ...
    except TypeError:
        # all TypeErrors end up here
    except TypeError:
        # this is *never* reached
    except ValueError:
        # all ValueErrors end up here
    except ValueError:
        # this is *never* reached
    
    相反,您应该在
    卡中提供具体的错误消息。当您实际
    引发
    错误并且已经知道原因时:

    if not isinstance(rank, int):  # better than comparing to type
        raise TypeError("The first parameter is not an integer")
    
    然后,您可以更简单地处理它们:

    try:
        c1 = Card(19,13)
    except (TypeError, ValueError) as err:  # assign the error to the name 'err'
        print(err)  # whichever we catch, show the user the message
    else:
        print(c1)  # only print the Card if there were no errors
    

    如果您特别需要区分同一类的不同错误,可以显式检查消息:

    except TypeError as err:
        if err.args[0] == "The first parameter is not an integer":
            # do whatever you need to
    
    或者创建您自己的、更具体的
    异常
    子类,这样您就可以拥有单独的
    异常
    块:

    class FirstParamNotIntError(Exception):
        pass
    
    (这只是一个例子,它们在您的特定案例中太具体了)



    可能值得一读。

    我只想补充一点,比较异常消息通常只能作为最后的手段,尤其是当引发异常的代码不是您的代码时。异常消息确实会被更改,因此它会创建非常脆弱的代码。当然不要害怕创建自己的异常(子)类,如果它允许您捕获有关错误的更好信息。谢谢您,Jonrsharpe。非常有用。我遵循了您的建议和您在上面发布的链接,但是如果我输入c1=Card(12,'h'),我最后的代码无法为我提供正确的输出,因为它仍然提供ValueError。对于我在诉讼中的第二个错误,我写了if suit!=self.suit:raise ValueError(“第二个参数的值不是集合中的一个……对于代码末尾的try/except,我使用c1=卡(12,'h')编写了相同的try。except(TypeError,ValueError)作为err:print(err)else:print(c1)。但是,它仍然给了我ValueError。我的代码有什么问题?@WuChu为什么你希望
    suit!=self.suit
    工作?!你刚刚检查的东西怎么可能是字符串等于字典?也许你应该看看。另外,对类属性和实例属性使用相同的名称是一个糟糕的举动。@jornsharpe好的,我可以将suit!=self.suit改成suit!='d'或'h'或'c'或's'或suit不在self.suit中。但是,对于类属性和实例属性的相同名称来说,什么是坏动作?这与为什么我输入c1=卡(13,'d')时没有得到正确的输出有关吗?这仍然是不正确的-你阅读了我刚才链接的问题吗?另外,我的意思是你正在使用例如
    rank
    作为有效列组列表和当前实例的列组。谢谢你,Jonrsharpe。非常有用。我遵循了你的建议和你上面发布的链接,但是如果我输入,我最后的代码不能给我正确的输出t c1=Card(12,'h'),因为它仍然给出ValueError。对于suit中的第二个ValueError,我写了if suit!=self.suit:raise ValueError(“第二个参数的值不是集合中的一个…”,对于代码末尾的try/except,我用c1=Card(12,'h')写了相同的try。除了(TypeError,ValueError)作为err:print(err)其他:打印(c1)。但是,它仍然给我ValueError。我的代码有什么问题?