代码之家  ›  专栏  ›  技术社区  ›  wim

为什么异常代理将str\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?

  •  3
  • wim  · 技术社区  · 7 年前

    为什么打印异常实例会打印 exc.args exc 直接?医生称之为 convenience 不便

    无法区分*args和元组之间的区别:

    >>> print(Exception(123, 456))
    (123, 456)
    >>> print(Exception((123, 456)))
    (123, 456)
    

    >>> print(Exception('123'))
    123
    >>> print(Exception(123))
    123
    

    还有可爱的“隐形”例外:

    >>> print(Exception())
    
    >>> 
    

    除非你明确要求不继承:

    >>> class MyError(Exception):
    ...     """an error in MyLibrary"""
    ...     
    >>> print(MyError())
    
    >>> 
    

    如果忘记用特定的方法记录错误实例,这可能是一个真正的问题 repr -日志文件中的默认字符串表示形式不可逆转地丢失了信息。

    这种奇怪的执行方式的理由是什么 Exception.__str__ exc.参数 那他们应该直接打印出来 exc.参数 ?

    1 回复  |  直到 7 年前
        1
  •  10
  •   Antti Haapala -- Слава Україні    7 年前

    BaseException.__str__ 可以用一种与python3向后不兼容的方式进行修复,以至少包含异常的类型,但是也许没有人注意到它是一个应该被修复的东西。

    目前的实施可追溯到PEP 0352,其中提供了基本原理:

    对可以传递的内容没有限制 args 因为向后兼容的原因。但实际上,只应使用单个字符串参数。这使得异常的字符串表示形式保持为关于异常的有用消息,这是人类可读的;这就是为什么 __str__ 方法特例长度1 参数 价值观。包括编程信息(例如,错误代码号)应作为单独的属性存储在子类中。

    当然,Python本身在许多情况下打破了有用的人类可读消息的这一原则——例如对 KeyError

    An error occurred: 42
    

    为什么 str(e) 本质上是 str(e.args) str(e.args[0]) ,引发异常的语法,例如 ValueError

    >>> raise ValueError, 'x must be positive'
    Traceback (innermost last):
      File "<stdin>", line 1
    ValueError: x must be positive
    

    Python 2.7版

    >>> raise ValueError, 'x must be positive'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: x must be positive
    

    同样,在 Python 1.0版 你会赶上火车的 值错误

    >>> try:
    ...     raise ValueError, 'foo'
    ... except ValueError, e:
    ...     print 'Got ValueError', e
    

    在Python2.7中工作不变。

    但是内部工作机制发生了变化:在Python1.0.1中, 值错误 是一个 一串 有价值的。。。 'ValueError'

    >>> ValueError, type(ValueError)
    ('ValueError', <type 'string'>)
    

    raise 以字符串作为鉴别器的单个参数或元组:

    >>> class MyCustomException: 
    ...     pass
    ...   
    >>> raise MyCustomException, 'my custom exception'
    Traceback (innermost last):
      File "<stdin>", line 1
    TypeError: exceptions must be strings
    

    >>> raise ValueError, ('invalid value for x', 42)
    Traceback (innermost last):
      File "<stdin>", line 1
    ValueError: ('invalid value for x', 42)
    

    如果你发现这个“例外” ,你得到了什么 e

    >>> try:
    ...     raise ValueError, ('invalid value for x', 42)
    ... except ValueError, e:
    ...     print e, type(e)
    ... 
    ('invalid value for x', 42) 42 <type 'tuple'>
    

    A 元组 !

    让我们试一下密码 :

    >>> try:
    ...     raise ValueError, ('invalid value for x', 42)
    ... except ValueError, e:
    ...     print e, e[1], type(e)
    ... 
    ('invalid value for x', 42) 42 <type 'exceptions.ValueError'>
    

    tuple 以前和现在都是例外。。。不仅如此 Exception __str公司__ 参数

    Python 2.7版

    >>> a, b, c = ValueError(1, 2, 3)
    >>> print a, b, c
    1 2 3
    

    所有这些黑客都是为了保持向后兼容性。

    BaseException PEP 0352 ; pep0352最初是在python2.5中实现的。


    raise discriminator, (arg, um, ents) ; 以及 except 只能使用 Exception as e

    pep0352讨论了放弃对多个参数的支持 基本异常 :

    会议决定,最好还是不赞成这一提议 message 属性(并在Python2.7和Python3.0中删除它),并考虑在Python3.0中使用更长期的转换策略,以删除中的多参数支持 宁愿只接受一个论点。因此,消息的引入和最初对 参数 已经收回。

    这似乎是对 参数 被遗忘了,因为它仍然存在于python3.7中,并且是 访问给定给许多内置异常的参数的方法。同样地 __str公司__ 不再需要委托给args,实际上可以为 BaseException.__repr__ 它给出了更好的,明确的表述:

    >>> BaseException.__str__(ValueError('foo', 'bar', 'baz'))
    "('foo', 'bar', 'baz')"
    >>> BaseException.__repr__(ValueError('foo', 'bar', 'baz'))
    "ValueError('foo', 'bar', 'baz')"
    

    但没人考虑过。


    另请注意 repr 一个例外是有用的-下次尝试打印您的例外与 !r 格式:

    print(f'Oops, I got a {e!r}')
    

    结果是

    ZeroDivisionError('division by zero',)
    

    正在输出。