wim*_*wim 5 python exception python-internals
为什么打印异常实例会打印值exc.args而不是exc直接表示?文档称之为便利,但实际上这实际上是一种不便.
无法区分*args和元组之间的区别:
>>> print(Exception(123, 456))
(123, 456)
>>> print(Exception((123, 456)))
(123, 456)
Run Code Online (Sandbox Code Playgroud)
无法可靠辨别类型:
>>> print(Exception('123'))
123
>>> print(Exception(123))
123
Run Code Online (Sandbox Code Playgroud)
和可爱的"隐形"例外:
>>> print(Exception())
>>>
Run Code Online (Sandbox Code Playgroud)
您将继承哪个,除非您明确要求不:
>>> class MyError(Exception):
... """an error in MyLibrary"""
...
>>> print(MyError())
>>>
Run Code Online (Sandbox Code Playgroud)
如果您忘记专门记录错误实例,这可能是一个真正的问题repr- 日志文件中的默认字符串表示具有不可逆转的丢失信息.
这种奇怪的实现的理由是Exception.__str__什么?据推测,如果用户想要打印,exc.args那么他们应该只打印exc.args?
Ant*_*ala 10
BaseException.__str__ 可能已经与Python 3以向后不兼容的方式修复,至少包括异常的类型,但也许没有人注意到它是一个应该修复的东西.
目前的实施可以追溯到PEP 0352,它提供了理由:
args出于向后兼容性的原因,对于可能传递的内容没有限制.但实际上,只应使用单个字符串参数.这使得异常的字符串表示形式成为关于人类可读异常的有用消息; 这就是为什么__str__方法特殊情况下长度为1的args值.包括程序信息(例如,错误代码编号)应该作为子类中的单独属性存储.
当然,在很多情况下,Python本身就打破了有用的人类可读消息的原则 - 例如,a的字符串化KeyError是未找到的密钥,这会导致调试消息,如
An error occurred: 42
Run Code Online (Sandbox Code Playgroud)
原因str(e)基本上str(e.args)或str(e.args[0])原本是向后兼容Python 1.0.在Python 1.0中,引发异常的语法,例如ValueError:
>>> raise ValueError, 'x must be positive'
Traceback (innermost last):
File "<stdin>", line 1
ValueError: x must be positive
Run Code Online (Sandbox Code Playgroud)
Python保留了向后兼容性1.0到2.7,因此你可以在Python 2.7中运行大多数Python 1.0程序(就像你从未想象的那样):
>>> raise ValueError, 'x must be positive'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: x must be positive
Run Code Online (Sandbox Code Playgroud)
同样,在Python的1.0,你会赶上ValueError与
>>> try:
... raise ValueError, 'foo'
... except ValueError, e:
... print 'Got ValueError', e
Run Code Online (Sandbox Code Playgroud)
在Python 2.7中没有改变.
但是内部工作方式的机制发生了变化:在Python 1.0.1中,ValueError是一个有价值的字符串 ......'ValueError'
>>> ValueError, type(ValueError)
('ValueError', <type 'string'>)
Run Code Online (Sandbox Code Playgroud)
根本没有异常类,你只能raise使用字符串作为鉴别器的单个参数或元组:
>>> class MyCustomException:
... pass
...
>>> raise MyCustomException, 'my custom exception'
Traceback (innermost last):
File "<stdin>", line 1
TypeError: exceptions must be strings
Run Code Online (Sandbox Code Playgroud)
也可以将元组作为参数:
>>> raise ValueError, ('invalid value for x', 42)
Traceback (innermost last):
File "<stdin>", line 1
ValueError: ('invalid value for x', 42)
Run Code Online (Sandbox Code Playgroud)
如果你在Python 1.0中捕获这个"异常" ,你得到的e是:
>>> try:
... raise ValueError, ('invalid value for x', 42)
... except ValueError, e:
... print e, type(e)
...
('invalid value for x', 42) 42 <type 'tuple'>
Run Code Online (Sandbox Code Playgroud)
一个元组!
我们来试试Python 2.7中的代码:
>>> 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'>
Run Code Online (Sandbox Code Playgroud)
除了值的类型外,输出看起来相同; 这是一个tuple之前和现在的异常......不仅Exception委托__str__给args成员,而且它还支持像元组那样的索引 - 以及解包,迭代等等:
Python 2.7
>>> a, b, c = ValueError(1, 2, 3)
>>> print a, b, c
1 2 3
Run Code Online (Sandbox Code Playgroud)
所有这些黑客都是为了保持向后兼容性.
Python 2.7行为来自PEP 0352BaseException中引入的类; PEP 0352最初是在Python 2.5中实现的.
在Python 3中,删除了旧语法 - 您无法使用raise discriminator, (arg, um, ents); 并且except只能使用Exception as e语法.
PEP 0352讨论了如何删除对多个参数的支持BaseException:
决定最好
message在Python 2.6中弃用该属性(并在Python 2.7和Python 3.0中删除它),并考虑在Python 3.0中使用更长期的过渡策略来删除多参数支持,BaseException而不是仅接受一个论点.因此,消息的引入和原始的弃用args已被收回.
似乎这种弃用args被遗忘了,因为它仍然存在于Python 3.7中,并且是访问许多内置异常的参数的唯一方法.同样__str__不再需要委托给args,并且实际上可以别名,BaseException.__repr__它提供了更好,更明确的表示:
>>> BaseException.__str__(ValueError('foo', 'bar', 'baz'))
"('foo', 'bar', 'baz')"
>>> BaseException.__repr__(ValueError('foo', 'bar', 'baz'))
"ValueError('foo', 'bar', 'baz')"
Run Code Online (Sandbox Code Playgroud)
但没有人考虑过它.
PS repr异常是有用的 - 下次尝试使用!r格式打印您的异常:
print(f'Oops, I got a {e!r}')
Run Code Online (Sandbox Code Playgroud)
结果
ZeroDivisionError('division by zero',)
Run Code Online (Sandbox Code Playgroud)
正在输出.
| 归档时间: |
|
| 查看次数: |
95 次 |
| 最近记录: |